mirror of
				https://github.com/topjohnwu/Magisk
				synced 2025-10-26 02:22:14 +01:00 
			
		
		
		
	Compare commits
	
		
			181 Commits
		
	
	
		
			canary-281
			...
			v29.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 62b1310d97 | ||
|   | 0a86916d3a | ||
|   | 9907ce57aa | ||
|   | b92626cacc | ||
|   | 5a762f0a8e | ||
|   | 5dd7a7d804 | ||
|   | 7831f40691 | ||
|   | 4f4b1ff885 | ||
|   | 97901979dd | ||
|   | 287316842c | ||
|   | 608786e8f3 | ||
|   | 9684a35cab | ||
|   | e3e4202954 | ||
|   | 23c2054d46 | ||
|   | a20a2a8fa0 | ||
|   | a2896be4a6 | ||
|   | e9220a28d9 | ||
|   | cf12087e21 | ||
|   | 00c1b36837 | ||
|   | 03e034795d | ||
|   | 79c0fafe43 | ||
|   | d499819ba0 | ||
|   | 86da917174 | ||
|   | 30bd7d6555 | ||
|   | e5a12f0f5f | ||
|   | c85a8434c6 | ||
|   | 427a1ca4e5 | ||
|   | 22884e173a | ||
|   | d1829308e9 | ||
|   | 73840f8721 | ||
|   | c7d1af9805 | ||
|   | 4ad26d3dfb | ||
|   | 0c70b7670c | ||
|   | f44d044095 | ||
|   | 5c1cb13472 | ||
|   | 3327fc668e | ||
|   | 610945ac54 | ||
|   | ddf5474917 | ||
|   | 6ba1685ade | ||
|   | e02b5f7868 | ||
|   | ab2e5d1e7e | ||
|   | f3fef7bfe4 | ||
|   | c34c7838bb | ||
|   | c8a16b0e0c | ||
|   | 14f9ed91a1 | ||
|   | 7a207d4ccf | ||
|   | 92a42d901f | ||
|   | 084d89fcce | ||
|   | 55b036c071 | ||
|   | 30e79310ab | ||
|   | f063fa5054 | ||
|   | 7bd901273c | ||
|   | c1e061603b | ||
|   | cb08504fe5 | ||
|   | c0a1fb77be | ||
|   | 4864c1112a | ||
|   | 9ddeab034b | ||
|   | c4847ed288 | ||
|   | b8f1523fb2 | ||
|   | fb7fa8a6b3 | ||
|   | 9c7d359093 | ||
|   | eb54bc1fd7 | ||
|   | d4a0286e13 | ||
|   | 83e66767ff | ||
|   | 7dc010749b | ||
|   | 8e8d013b1b | ||
|   | bba0373808 | ||
|   | 1fa318dc8c | ||
|   | 6edc5e2037 | ||
|   | 1523ed9f78 | ||
|   | 8e604d2ab8 | ||
|   | 2aba7247a9 | ||
|   | e66fe8533e | ||
|   | b03fbb3917 | ||
|   | c2ece62e4c | ||
|   | 8c972dcf34 | ||
|   | 50af14f2a3 | ||
|   | e0a356b319 | ||
|   | c09a792958 | ||
|   | 0bbfe7f44d | ||
|   | a396abf565 | ||
|   | 1e3edb8883 | ||
|   | 3b8b61bf35 | ||
|   | 6f90456036 | ||
|   | f56fd4e215 | ||
|   | aa35aac5d5 | ||
|   | 1f162b819d | ||
|   | 52ef1d1cb2 | ||
|   | f14e3a89cc | ||
|   | 95d3eac2e0 | ||
|   | 8e73536e02 | ||
|   | 12a0870bc9 | ||
|   | 6ff82c4e86 | ||
|   | c64de35375 | ||
|   | ee5283f4e8 | ||
|   | bd0e954fea | ||
|   | 675471a49e | ||
|   | c90e73ccec | ||
|   | a43c1267d8 | ||
|   | e8958c6b5c | ||
|   | e8a3bf82c6 | ||
|   | 27fd79176a | ||
|   | 28d86a3454 | ||
|   | c6c1a17ae6 | ||
|   | 2b47d47215 | ||
|   | 0e82df9e10 | ||
|   | 893821ad88 | ||
|   | 6b80fbfa99 | ||
|   | 8c3c7d0194 | ||
|   | b94a3d9f2f | ||
|   | 442d0b5ddc | ||
|   | 494615d9a0 | ||
|   | afbfb81837 | ||
|   | 3ed4e258a3 | ||
|   | dddd41c95b | ||
|   | 5f2ca81e86 | ||
|   | c9eac0c438 | ||
|   | b6b34f7612 | ||
|   | e55c413261 | ||
|   | 0399cde50a | ||
|   | 019eb03823 | ||
|   | 363410e1c0 | ||
|   | fc2ef21660 | ||
|   | 18cb659ff3 | ||
|   | 63231d97ce | ||
|   | 9ac81a8a25 | ||
|   | 79af2787ae | ||
|   | f5f9b285c0 | ||
|   | 6c05f2ae85 | ||
|   | 29043e1684 | ||
|   | b73d4a7022 | ||
|   | ad95e8951b | ||
|   | bf591fca12 | ||
|   | dcf027884d | ||
|   | 584f3820fe | ||
|   | 3c7c46307a | ||
|   | 4d80361805 | ||
|   | 9a74e19117 | ||
|   | b1e17706a4 | ||
|   | caad129d69 | ||
|   | da58571ce5 | ||
|   | 2aa7f1c094 | ||
|   | 823e31a91b | ||
|   | fb926ae302 | ||
|   | e0489eeffd | ||
|   | dc9d5a4cac | ||
|   | 143743d0b0 | ||
|   | 563f0d5ad5 | ||
|   | c99f4a591b | ||
|   | 449204e380 | ||
|   | a85c4c6528 | ||
|   | d203a6fff6 | ||
|   | 6c612d66d7 | ||
|   | 540253a55b | ||
|   | 15b7c4ccd1 | ||
|   | 442d5335ea | ||
|   | 8a80eea597 | ||
|   | 5e35703091 | ||
|   | b7ca73f431 | ||
|   | a14fc90f07 | ||
|   | c913f7ec74 | ||
|   | 7f6c9e8411 | ||
|   | bb02ea3a20 | ||
|   | 3981c9665e | ||
|   | 88628fdf3c | ||
|   | 0469817781 | ||
|   | a786801141 | ||
|   | ab86732c89 | ||
|   | 59622d1688 | ||
|   | 58a25a3e2b | ||
|   | 15dca29a87 | ||
|   | 46980819c0 | ||
|   | 4fb6a7268c | ||
|   | c05e963f37 | ||
|   | 7f7f625864 | ||
|   | b25aa8295a | ||
|   | 15a605765c | ||
|   | b575c95710 | ||
|   | a48a9c858a | ||
|   | 0d8d6290a3 | ||
|   | 4dcd733ddd | 
							
								
								
									
										6
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							| @@ -12,13 +12,11 @@ | ||||
|  | ||||
| # Denote all files that are truly binary and should not be modified. | ||||
| tools/** binary | ||||
| tools/rustup-wrapper/** -binary | ||||
| tools/elf-cleaner/** -binary | ||||
| *.jar binary | ||||
| *.exe binary | ||||
| *.apk binary | ||||
| *.png binary | ||||
| *.jpg binary | ||||
| *.ttf binary | ||||
|  | ||||
| # Help GitHub detect languages | ||||
| native/jni/external/** linguist-vendored | ||||
| native/jni/systemproperties/** linguist-language=C++ | ||||
|   | ||||
							
								
								
									
										23
									
								
								.github/actions/setup/action.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								.github/actions/setup/action.yml
									
									
									
									
										vendored
									
									
								
							| @@ -26,6 +26,15 @@ runs: | ||||
|  | ||||
|     - name: Cache sccache | ||||
|       uses: actions/cache@v4 | ||||
|       if: ${{ github.event_name != 'pull_request' }} | ||||
|       with: | ||||
|         path: .sccache | ||||
|         key: sccache-${{ runner.os }}-${{ github.sha }} | ||||
|         restore-keys: sccache-${{ runner.os }}- | ||||
|  | ||||
|     - name: Restore sccache | ||||
|       uses: actions/cache/restore@v4 | ||||
|       if: ${{ github.event_name == 'pull_request' }} | ||||
|       with: | ||||
|         path: .sccache | ||||
|         key: sccache-${{ runner.os }}-${{ github.sha }} | ||||
| @@ -55,7 +64,7 @@ runs: | ||||
|  | ||||
|     - name: Cache Gradle dependencies | ||||
|       uses: actions/cache@v4 | ||||
|       if: inputs.is-asset-build == 'true' | ||||
|       if: ${{ inputs.is-asset-build == 'true' && github.event_name != 'pull_request' }} | ||||
|       with: | ||||
|         path: | | ||||
|           .gradle/caches | ||||
| @@ -66,7 +75,7 @@ runs: | ||||
|  | ||||
|     - name: Restore Gradle dependencies | ||||
|       uses: actions/cache/restore@v4 | ||||
|       if: inputs.is-asset-build == 'false' | ||||
|       if: ${{ inputs.is-asset-build == 'false' || github.event_name == 'pull_request' }} | ||||
|       with: | ||||
|         path: | | ||||
|           .gradle/caches | ||||
| @@ -78,19 +87,17 @@ runs: | ||||
|  | ||||
|     - name: Cache Gradle build cache | ||||
|       uses: actions/cache@v4 | ||||
|       if: inputs.is-asset-build == 'true' | ||||
|       if: ${{ inputs.is-asset-build == 'true' && github.event_name != 'pull_request' }} | ||||
|       with: | ||||
|         path: | | ||||
|           .gradle/caches/build-cache-* | ||||
|         path: .gradle/caches/build-cache-* | ||||
|         key: gradle-build-cache-${{ github.sha }} | ||||
|         restore-keys: gradle-build-cache- | ||||
|  | ||||
|     - name: Restore Gradle build cache | ||||
|       uses: actions/cache/restore@v4 | ||||
|       if: inputs.is-asset-build == 'false' | ||||
|       if: ${{ inputs.is-asset-build == 'false' || github.event_name == 'pull_request' }} | ||||
|       with: | ||||
|         path: | | ||||
|           .gradle/caches/build-cache-* | ||||
|         path: .gradle/caches/build-cache-* | ||||
|         key: gradle-build-cache-${{ github.sha }} | ||||
|         restore-keys: gradle-build-cache- | ||||
|         enableCrossOsArchive: true | ||||
|   | ||||
							
								
								
									
										24
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,13 @@ | ||||
| name: Magisk Build | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: [master] | ||||
|     paths: | ||||
|       - "app/**" | ||||
|       - "native/**" | ||||
|       - "build.py" | ||||
|       - ".github/workflows/build.yml" | ||||
|   pull_request: | ||||
|     branches: [master] | ||||
|   workflow_dispatch: | ||||
| @@ -29,7 +36,7 @@ jobs: | ||||
|         run: ./build.py -v all | ||||
|  | ||||
|       - name: Stop gradle daemon | ||||
|         run: ./gradlew --stop | ||||
|         run: ./app/gradlew --stop | ||||
|  | ||||
|       - name: Upload build artifact | ||||
|         uses: actions/upload-artifact@v4 | ||||
| @@ -65,21 +72,22 @@ jobs: | ||||
|         run: python build.py -v -c .github/ci.prop all | ||||
|  | ||||
|       - name: Stop gradle daemon | ||||
|         run: ./gradlew --stop | ||||
|         run: ./app/gradlew --stop | ||||
|  | ||||
|   avd-test: | ||||
|     name: Test API ${{ matrix.version }} (x86_64) | ||||
|     runs-on: ubuntu-24.04 | ||||
|     needs: build | ||||
|     if: ${{ github.event_name != 'push' }} | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35] | ||||
|         type: [""] | ||||
|         include: | ||||
|           - version: "Baklava" | ||||
|           - version: 36 | ||||
|             type: "google_apis" | ||||
|           - version: "Baklava" | ||||
|           - version: 36 | ||||
|             type: "google_apis_ps16k" | ||||
|  | ||||
|     steps: | ||||
| @@ -117,6 +125,7 @@ jobs: | ||||
|     name: Test API ${{ matrix.version }} (x86) | ||||
|     runs-on: ubuntu-24.04 | ||||
|     needs: build | ||||
|     if: ${{ github.event_name != 'push' }} | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
| @@ -158,14 +167,15 @@ jobs: | ||||
|     name: Test ${{ matrix.device }} | ||||
|     runs-on: ubuntu-24.04 | ||||
|     needs: build | ||||
|     if: ${{ github.event_name != 'push' }} | ||||
|     env: | ||||
|       CF_HOME: /home/runner/aosp_cf_phone | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         include: | ||||
|           - branch: "aosp-main" | ||||
|             device: "aosp_cf_x86_64_phone" | ||||
|           - branch: "aosp-android-latest-release" | ||||
|             device: "aosp_cf_x86_64_only_phone" | ||||
|  | ||||
|     steps: | ||||
|       - name: Check out | ||||
| @@ -184,7 +194,7 @@ jobs: | ||||
|  | ||||
|       - name: Run Cuttlefish test | ||||
|         timeout-minutes: 10 | ||||
|         run: su $USER -c 'scripts/cuttlefish.sh test' | ||||
|         run: sudo -E -u $USER scripts/cuttlefish.sh test | ||||
|  | ||||
|       - name: Upload logs on error | ||||
|         if: ${{ failure() }} | ||||
|   | ||||
							
								
								
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -2,19 +2,13 @@ out | ||||
| *.zip | ||||
| *.jks | ||||
| *.apk | ||||
| *.log | ||||
| /config.prop | ||||
| /notes.md | ||||
| /update.sh | ||||
| /app/dict.txt | ||||
|  | ||||
| # Built binaries | ||||
| native/out | ||||
|  | ||||
| # Android Studio / Gradle | ||||
| # Android Studio | ||||
| *.iml | ||||
| .gradle | ||||
| .idea | ||||
| .kotlin | ||||
| /local.properties | ||||
| /build | ||||
| /captures | ||||
|   | ||||
							
								
								
									
										9
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -4,18 +4,12 @@ | ||||
| [submodule "lz4"] | ||||
| 	path = native/src/external/lz4 | ||||
| 	url = https://github.com/lz4/lz4.git | ||||
| [submodule "bzip2"] | ||||
| 	path = native/src/external/bzip2 | ||||
| 	url = https://github.com/nemequ/bzip2.git | ||||
| [submodule "xz"] | ||||
| 	path = native/src/external/xz | ||||
| 	url = https://github.com/xz-mirror/xz.git | ||||
| [submodule "libcxx"] | ||||
| 	path = native/src/external/libcxx | ||||
| 	url = https://github.com/topjohnwu/libcxx.git | ||||
| [submodule "zlib"] | ||||
| 	path = native/src/external/zlib | ||||
| 	url = https://android.googlesource.com/platform/external/zlib | ||||
| [submodule "zopfli"] | ||||
| 	path = native/src/external/zopfli | ||||
| 	url = https://github.com/google/zopfli.git | ||||
| @@ -31,6 +25,3 @@ | ||||
| [submodule "crt0"] | ||||
| 	path = native/src/external/crt0 | ||||
| 	url = https://github.com/topjohnwu/crt0.git | ||||
| [submodule "termux-elf-cleaner"] | ||||
| 	path = tools/termux-elf-cleaner | ||||
| 	url = https://github.com/termux/termux-elf-cleaner.git | ||||
|   | ||||
| @@ -21,8 +21,8 @@ Some highlight features: | ||||
| Click the icon below to download Magisk apk. | ||||
|  | ||||
| [](https://github.com/topjohnwu/Magisk/releases/tag/v28.1) | ||||
| [](https://github.com/topjohnwu/Magisk/releases/tag/v28.1) | ||||
| [](https://github.com/topjohnwu/Magisk/releases/tag/canary-28102) | ||||
| [](https://github.com/topjohnwu/Magisk/releases/tag/v29.0) | ||||
| [](https://github.com/topjohnwu/Magisk/releases/tag/canary-28104) | ||||
|  | ||||
| ## Useful Links | ||||
|  | ||||
|   | ||||
							
								
								
									
										7
									
								
								app/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| /dict.txt | ||||
|  | ||||
| # Gradle | ||||
| .gradle | ||||
| .kotlin | ||||
| /local.properties | ||||
| /build | ||||
| @@ -35,7 +35,7 @@ android { | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     implementation(project(":app:core")) | ||||
|     implementation(project(":core")) | ||||
|     coreLibraryDesugaring(libs.jdk.libs) | ||||
|  | ||||
|     implementation(libs.indeterminate.checkbox) | ||||
|   | ||||
| @@ -1,10 +1,13 @@ | ||||
| package com.topjohnwu.magisk.arch | ||||
|  | ||||
| import android.content.ContentResolver | ||||
| import android.view.KeyEvent | ||||
| import androidx.databinding.ViewDataBinding | ||||
| import androidx.navigation.NavController | ||||
| import androidx.navigation.NavDirections | ||||
| import androidx.navigation.fragment.NavHostFragment | ||||
| import androidx.navigation.navOptions | ||||
| import com.topjohnwu.magisk.utils.AccessibilityUtils | ||||
|  | ||||
| abstract class NavigationActivity<Binding : ViewDataBinding> : UIActivity<Binding>() { | ||||
|  | ||||
| @@ -31,7 +34,17 @@ abstract class NavigationActivity<Binding : ViewDataBinding> : UIActivity<Bindin | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         fun navigate(directions: NavDirections, navigation: NavController, cr: ContentResolver) { | ||||
|             if (AccessibilityUtils.isAnimationEnabled(cr)) { | ||||
|                 navigation.navigate(directions) | ||||
|             } else { | ||||
|                 navigation.navigate(directions, navOptions {}) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun NavDirections.navigate() { | ||||
|         navigation.navigate(this) | ||||
|         navigate(this, navigation, contentResolver) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -17,6 +17,8 @@ import com.topjohnwu.magisk.core.Info | ||||
| import com.topjohnwu.magisk.core.download.DownloadEngine | ||||
| import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding | ||||
| import com.topjohnwu.magisk.core.R as CoreR | ||||
| import androidx.navigation.findNavController | ||||
| import com.topjohnwu.magisk.arch.NavigationActivity | ||||
|  | ||||
| class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider { | ||||
|  | ||||
| @@ -68,7 +70,13 @@ class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider { | ||||
|     override fun onMenuItemSelected(item: MenuItem): Boolean { | ||||
|         when (item.itemId) { | ||||
|             R.id.action_settings -> | ||||
|                 HomeFragmentDirections.actionHomeFragmentToSettingsFragment().navigate() | ||||
|                 activity?.let { | ||||
|                     NavigationActivity.navigate( | ||||
|                         HomeFragmentDirections.actionHomeFragmentToSettingsFragment(), | ||||
|                         it.findNavController(R.id.main_nav_host), | ||||
|                         it.contentResolver, | ||||
|                     ) | ||||
|                 } | ||||
|             R.id.action_reboot -> activity?.let { RebootMenu.inflate(it).show() } | ||||
|             else -> return super.onOptionsItemSelected(item) | ||||
|         } | ||||
|   | ||||
| @@ -41,7 +41,7 @@ object RebootMenu { | ||||
|             activity.getSystemService<PowerManager>()?.isRebootingUserspaceSupported == true) { | ||||
|             menu.menu.findItem(R.id.action_reboot_userspace).isVisible = true | ||||
|         } | ||||
|         if (Const.Version.isCanary()) { | ||||
|         if (Const.Version.atLeast_28_0()) { | ||||
|             menu.menu.findItem(R.id.action_reboot_safe_mode).isChecked = Config.bootloop >= 2 | ||||
|         } else { | ||||
|             menu.menu.findItem(R.id.action_reboot_safe_mode).isVisible = false | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import android.view.Menu | ||||
| import android.view.MenuInflater | ||||
| import android.view.MenuItem | ||||
| import android.view.View | ||||
| import android.widget.HorizontalScrollView | ||||
| import androidx.core.view.MenuProvider | ||||
| import androidx.core.view.isVisible | ||||
| import com.topjohnwu.magisk.R | ||||
| @@ -12,6 +13,7 @@ import com.topjohnwu.magisk.arch.BaseFragment | ||||
| import com.topjohnwu.magisk.arch.viewModel | ||||
| import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding | ||||
| import com.topjohnwu.magisk.ui.MainActivity | ||||
| import com.topjohnwu.magisk.utils.AccessibilityUtils | ||||
| import com.topjohnwu.magisk.utils.MotionRevealHelper | ||||
| import rikka.recyclerview.addEdgeSpacing | ||||
| import rikka.recyclerview.addItemSpacing | ||||
| @@ -56,6 +58,11 @@ class LogFragment : BaseFragment<FragmentLogMd2Binding>(), MenuProvider { | ||||
|             addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1) | ||||
|             fixEdgeEffect() | ||||
|         } | ||||
|  | ||||
|         if (!AccessibilityUtils.isAnimationEnabled(requireContext().contentResolver)) { | ||||
|             val scrollView = view.findViewById<HorizontalScrollView>(R.id.log_scroll_magisk) | ||||
|             scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,14 @@ | ||||
| package com.topjohnwu.magisk.utils | ||||
|  | ||||
| import android.content.ContentResolver | ||||
| import android.provider.Settings | ||||
|  | ||||
| class AccessibilityUtils { | ||||
|     companion object { | ||||
|         fun isAnimationEnabled(cr: ContentResolver): Boolean { | ||||
|             return !(Settings.Global.getFloat(cr, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f) == 0.0f | ||||
|                 && Settings.Global.getFloat(cr, Settings.Global.TRANSITION_ANIMATION_SCALE, 1.0f) == 0.0f | ||||
|                 && Settings.Global.getFloat(cr, Settings.Global.WINDOW_ANIMATION_SCALE, 1.0f) == 0.0f) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -16,6 +16,7 @@ | ||||
|         android:layout_height="match_parent"> | ||||
|  | ||||
|         <HorizontalScrollView | ||||
|             android:id="@+id/log_scroll_magisk" | ||||
|             gone="@{viewModel.loading}" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|   | ||||
| @@ -1,5 +1,11 @@ | ||||
| tasks.register("clean") { | ||||
| plugins { | ||||
|     id("MagiskPlugin") | ||||
| } | ||||
|  | ||||
| tasks.register("clean", Delete::class) { | ||||
|     delete(rootProject.layout.buildDirectory) | ||||
|  | ||||
|     subprojects.forEach { | ||||
|         dependsOn(":app:${it.name}:clean") | ||||
|         dependsOn(":${it.name}:clean") | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -14,7 +14,7 @@ private val defaultAbis = setOf("armeabi-v7a", "x86", "arm64-v8a", "x86_64") | ||||
| object Config { | ||||
|     operator fun get(key: String): String? { | ||||
|         val v = props[key] as? String ?: return null | ||||
|         return if (v.isBlank()) null else v | ||||
|         return v.ifBlank { null } | ||||
|     } | ||||
|  | ||||
|     fun contains(key: String) = get(key) != null | ||||
| @@ -28,19 +28,21 @@ object Config { | ||||
|     } | ||||
| } | ||||
|  | ||||
| val Project.baseDir: File get() = rootProject.file("..") | ||||
|  | ||||
| class MagiskPlugin : Plugin<Project> { | ||||
|     override fun apply(project: Project) = project.applyPlugin() | ||||
|  | ||||
|     private fun Project.applyPlugin() { | ||||
|         initRandom(rootProject.file("app/dict.txt")) | ||||
|         initRandom(rootProject.file("dict.txt")) | ||||
|         props.clear() | ||||
|         rootProject.file("gradle.properties").inputStream().use { props.load(it) } | ||||
|         val configPath: String? by this | ||||
|         val config = configPath?.let { File(it) } ?: rootProject.file("config.prop") | ||||
|         val config = configPath?.let { File(it) } ?: File(baseDir, "config.prop") | ||||
|         if (config.exists()) | ||||
|             config.inputStream().use { props.load(it) } | ||||
|  | ||||
|         val repo = FileRepository(rootProject.file(".git")) | ||||
|         val repo = FileRepository(File(baseDir, ".git")) | ||||
|         val refId = repo.refDatabase.exactRef("HEAD").objectId | ||||
|         commitHash = repo.newObjectReader().abbreviate(refId, 8).name() | ||||
|     } | ||||
| @@ -71,10 +71,10 @@ private val Project.androidComponents | ||||
|  | ||||
| fun Project.setupCommon() { | ||||
|     androidBase { | ||||
|         compileSdkVersion(35) | ||||
|         buildToolsVersion = "35.0.1" | ||||
|         compileSdkVersion(36) | ||||
|         buildToolsVersion = "36.0.0" | ||||
|         ndkPath = "$sdkDirectory/ndk/magisk" | ||||
|         ndkVersion = "28.0.12674087" | ||||
|         ndkVersion = "29.0.13113456" | ||||
|  | ||||
|         defaultConfig { | ||||
|             minSdk = 23 | ||||
| @@ -89,6 +89,7 @@ fun Project.setupCommon() { | ||||
|             resources { | ||||
|                 excludes += arrayOf( | ||||
|                     "/META-INF/*", | ||||
|                     "/META-INF/androidx/**", | ||||
|                     "/META-INF/versions/**", | ||||
|                     "/org/bouncycastle/**", | ||||
|                     "/org/apache/commons/**", | ||||
| @@ -115,6 +116,27 @@ fun Project.setupCommon() { | ||||
|     } | ||||
| } | ||||
|  | ||||
| private fun Project.downloadFile(url: String, checksum: String): File { | ||||
|     val file = layout.buildDirectory.file(checksum).get().asFile | ||||
|     if (file.exists()) { | ||||
|         val md = MessageDigest.getInstance("SHA-256") | ||||
|         file.inputStream().use { md.update(it.readAllBytes()) } | ||||
|         val hash = HexFormat.of().formatHex(md.digest()) | ||||
|         if (hash != checksum) { | ||||
|             file.delete() | ||||
|         } | ||||
|     } | ||||
|     if (!file.exists()) { | ||||
|         file.parentFile.mkdirs() | ||||
|         URI(url).toURL().openStream().use { dl -> | ||||
|             file.outputStream().use { | ||||
|                 dl.copyTo(it) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return file | ||||
| } | ||||
|  | ||||
| const val BUSYBOX_DOWNLOAD_URL = | ||||
|     "https://github.com/topjohnwu/magisk-files/releases/download/files/busybox-1.36.1.1.zip" | ||||
| const val BUSYBOX_ZIP_CHECKSUM = | ||||
| @@ -129,7 +151,7 @@ fun Project.setupCoreLib() { | ||||
|         into("src/main/jniLibs") | ||||
|         for (abi in abiList) { | ||||
|             into(abi) { | ||||
|                 from(rootProject.file("native/out/$abi")) { | ||||
|                 from(File(baseDir, "native/out/$abi")) { | ||||
|                     include("magiskboot", "magiskinit", "magiskpolicy", "magisk", "libinit-ld.so") | ||||
|                     rename { if (it.endsWith(".so")) it else "lib$it.so" } | ||||
|                 } | ||||
| @@ -144,34 +166,17 @@ fun Project.setupCoreLib() { | ||||
|  | ||||
|     val downloadBusybox by tasks.registering(Copy::class) { | ||||
|         dependsOn(syncLibs) | ||||
|         val bb = layout.buildDirectory.file(BUSYBOX_ZIP_CHECKSUM).get().asFile | ||||
|         if (bb.exists()) { | ||||
|             val md = MessageDigest.getInstance("SHA-256") | ||||
|             bb.inputStream().use { md.update(it.readAllBytes()) } | ||||
|             val hash = HexFormat.of().formatHex(md.digest()) | ||||
|             if (hash != BUSYBOX_ZIP_CHECKSUM) { | ||||
|                 bb.delete() | ||||
|             } | ||||
|         } | ||||
|         if (!bb.exists()) { | ||||
|             bb.parentFile.mkdirs() | ||||
|             URI(BUSYBOX_DOWNLOAD_URL).toURL().openStream().use { dl -> | ||||
|                 bb.outputStream().use { | ||||
|                     dl.copyTo(it) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         from(zipTree(bb)) | ||||
|         from(zipTree(downloadFile(BUSYBOX_DOWNLOAD_URL, BUSYBOX_ZIP_CHECKSUM))) | ||||
|         include(abiList.map { "$it/libbusybox.so" }) | ||||
|         into("src/main/jniLibs") | ||||
|     } | ||||
|  | ||||
|     val syncResources by tasks.registering(Sync::class) { | ||||
|         into("src/main/resources/META-INF/com/google/android") | ||||
|         from(rootProject.file("scripts/update_binary.sh")) { | ||||
|         from(File(baseDir, "scripts/update_binary.sh")) { | ||||
|             rename { "update-binary" } | ||||
|         } | ||||
|         from(rootProject.file("scripts/flash_script.sh")) { | ||||
|         from(File(baseDir, "scripts/flash_script.sh")) { | ||||
|             rename { "updater-script" } | ||||
|         } | ||||
|     } | ||||
| @@ -182,7 +187,7 @@ fun Project.setupCoreLib() { | ||||
|         tasks.getByPath("merge${variantCapped}JniLibFolders").dependsOn(downloadBusybox) | ||||
|         processJavaResourcesProvider.configure { dependsOn(syncResources) } | ||||
|  | ||||
|         val stubTask = tasks.getByPath(":app:stub:comment$variantCapped") | ||||
|         val stubTask = tasks.getByPath(":stub:comment$variantCapped") | ||||
|         val stubApk = stubTask.outputs.files.asFileTree.filter { | ||||
|             it.name.endsWith(".apk") | ||||
|         } | ||||
| @@ -192,14 +197,14 @@ fun Project.setupCoreLib() { | ||||
|             inputs.property("version", Config.version) | ||||
|             inputs.property("versionCode", Config.versionCode) | ||||
|             into("src/${this@all.name}/assets") | ||||
|             from(rootProject.file("scripts")) { | ||||
|             from(File(baseDir, "scripts")) { | ||||
|                 include("util_functions.sh", "boot_patch.sh", "addon.d.sh", | ||||
|                     "app_functions.sh", "uninstaller.sh", "module_installer.sh") | ||||
|             } | ||||
|             from(rootProject.file("tools/bootctl")) | ||||
|             from(File(baseDir, "tools/bootctl")) | ||||
|             into("chromeos") { | ||||
|                 from(rootProject.file("tools/futility")) | ||||
|                 from(rootProject.file("tools/keys")) { | ||||
|                 from(File(baseDir, "tools/futility")) | ||||
|                 from(File(baseDir, "tools/keys")) { | ||||
|                     include("kernel_data_key.vbprivk", "kernel.keyblock") | ||||
|                 } | ||||
|             } | ||||
| @@ -289,7 +294,7 @@ fun Project.setupAppCommon() { | ||||
|         signingConfigs { | ||||
|             create("config") { | ||||
|                 Config["keyStore"]?.also { | ||||
|                     storeFile = rootProject.file(it) | ||||
|                     storeFile = File(baseDir, it) | ||||
|                     storePassword = Config["keyStorePass"] | ||||
|                     keyAlias = Config["keyAlias"] | ||||
|                     keyPassword = Config["keyPass"] | ||||
| @@ -298,7 +303,7 @@ fun Project.setupAppCommon() { | ||||
|         } | ||||
|  | ||||
|         defaultConfig { | ||||
|             targetSdk = 35 | ||||
|             targetSdk = 36 | ||||
|             proguardFiles( | ||||
|                 getDefaultProguardFile("proguard-android-optimize.txt") | ||||
|             ) | ||||
| @@ -462,3 +467,31 @@ fun Project.setupStubApk() { | ||||
|         delete.addAll(listOf("src/debug/AndroidManifest.xml", "src/release/AndroidManifest.xml")) | ||||
|     } | ||||
| } | ||||
|  | ||||
| const val LSPOSED_DOWNLOAD_URL = | ||||
|     "https://github.com/LSPosed/LSPosed/releases/download/v1.9.2/LSPosed-v1.9.2-7024-zygisk-release.zip" | ||||
| const val LSPOSED_CHECKSUM = | ||||
|     "0ebc6bcb465d1c4b44b7220ab5f0252e6b4eb7fe43da74650476d2798bb29622" | ||||
|  | ||||
| const val SHAMIKO_DOWNLOAD_URL = | ||||
|     "https://github.com/LSPosed/LSPosed.github.io/releases/download/shamiko-383/Shamiko-v1.2.1-383-release.zip" | ||||
| const val SHAMIKO_CHECKSUM = | ||||
|     "93754a038c2d8f0e985bad45c7303b96f70a93d8335060e50146f028d3a9b13f" | ||||
|  | ||||
| fun Project.setupTestApk() { | ||||
|     setupAppCommon() | ||||
|  | ||||
|     androidApp.applicationVariants.all { | ||||
|         val variantCapped = name.replaceFirstChar { it.uppercase() } | ||||
|         val dlTask by tasks.register("download${variantCapped}Lsposed", Sync::class) { | ||||
|             from(downloadFile(LSPOSED_DOWNLOAD_URL, LSPOSED_CHECKSUM)) { | ||||
|                 rename { "lsposed.zip" } | ||||
|             } | ||||
|             from(downloadFile(SHAMIKO_DOWNLOAD_URL, SHAMIKO_CHECKSUM)) { | ||||
|                 rename { "shamiko.zip" } | ||||
|             } | ||||
|             into("src/${this@all.name}/assets") | ||||
|         } | ||||
|         mergeAssetsProvider.configure { dependsOn(dlTask) } | ||||
|     } | ||||
| } | ||||
| @@ -29,7 +29,7 @@ android { | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     api(project(":app:shared")) | ||||
|     api(project(":shared")) | ||||
|  | ||||
|     api(libs.timber) | ||||
|     api(libs.markwon.core) | ||||
|   | ||||
| @@ -14,7 +14,6 @@ | ||||
|     <application | ||||
|         android:name=".App" | ||||
|         android:icon="@drawable/ic_launcher" | ||||
|         android:multiArch="true" | ||||
|         tools:ignore="UnusedAttribute,GoogleAppIndexingWarning" | ||||
|         tools:remove="android:appComponentFactory"> | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,7 @@ object Const { | ||||
|         else Build.SUPPORTED_32_BIT_ABIS.firstOrNull() | ||||
|  | ||||
|     // Paths | ||||
|     const val MAGISK_PATH  = "/data/adb/modules" | ||||
|     const val MODULE_PATH  = "/data/adb/modules" | ||||
|     const val TMPDIR = "/dev/tmp" | ||||
|     const val MAGISK_LOG = "/cache/magisk.log" | ||||
|  | ||||
| @@ -28,6 +28,7 @@ object Const { | ||||
|  | ||||
|         fun atLeast_24_0() = Info.env.versionCode >= 24000 || isCanary() | ||||
|         fun atLeast_25_0() = Info.env.versionCode >= 25000 || isCanary() | ||||
|         fun atLeast_28_0() = Info.env.versionCode >= 28000 || isCanary() | ||||
|         fun isCanary() = isCanary(Info.env.versionCode) | ||||
|  | ||||
|         fun isCanary(ver: Int) = ver > 0 && ver % 100 != 0 | ||||
|   | ||||
| @@ -47,7 +47,6 @@ object Info { | ||||
|         private set | ||||
|     private var crypto = "" | ||||
|  | ||||
|     var hasGMS = true | ||||
|     val isEmulator = | ||||
|         Build.DEVICE.contains("vsoc") | ||||
|             || getProperty("ro.kernel.qemu", "0") == "1" | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import com.squareup.moshi.Moshi | ||||
| import com.topjohnwu.magisk.ProviderInstaller | ||||
| import com.topjohnwu.magisk.core.BuildConfig | ||||
| import com.topjohnwu.magisk.core.Config | ||||
| import com.topjohnwu.magisk.core.Info | ||||
| import com.topjohnwu.magisk.core.utils.LocaleSetting | ||||
| import okhttp3.Cache | ||||
| import okhttp3.ConnectionSpec | ||||
| @@ -72,9 +71,7 @@ fun createOkHttpClient(context: Context): OkHttpClient { | ||||
|         chain.proceed(request.build()) | ||||
|     } | ||||
|  | ||||
|     if (!ProviderInstaller.install(context)) { | ||||
|         Info.hasGMS = false | ||||
|     } | ||||
|     ProviderInstaller.install(context) | ||||
|  | ||||
|     return builder.build() | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import com.topjohnwu.magisk.core.Const | ||||
| import com.topjohnwu.magisk.core.di.ServiceLocator | ||||
| import com.topjohnwu.magisk.core.utils.RootUtils | ||||
| import com.topjohnwu.superuser.Shell | ||||
| import com.topjohnwu.superuser.nio.ExtendedFile | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.withContext | ||||
| import timber.log.Timber | ||||
| @@ -12,7 +13,7 @@ import java.io.IOException | ||||
| import java.util.Locale | ||||
|  | ||||
| data class LocalModule( | ||||
|     private val path: String, | ||||
|     private val base: ExtendedFile, | ||||
| ) : Module() { | ||||
|     private val svc get() = ServiceLocator.networkService | ||||
|  | ||||
| @@ -24,20 +25,18 @@ data class LocalModule( | ||||
|     var description: String = "" | ||||
|     var updateInfo: OnlineModule? = null | ||||
|     var outdated = false | ||||
|  | ||||
|     private var updateUrl: String = "" | ||||
|     private val removeFile = RootUtils.fs.getFile(path, "remove") | ||||
|     private val disableFile = RootUtils.fs.getFile(path, "disable") | ||||
|     private val updateFile = RootUtils.fs.getFile(path, "update") | ||||
|     private val riruFolder = RootUtils.fs.getFile(path, "riru") | ||||
|     private val zygiskFolder = RootUtils.fs.getFile(path, "zygisk") | ||||
|     private val unloaded = RootUtils.fs.getFile(zygiskFolder, "unloaded") | ||||
|  | ||||
|     val updated: Boolean get() = updateFile.exists() | ||||
|     val isRiru: Boolean get() = (id == "riru-core") || riruFolder.exists() | ||||
|     val isZygisk: Boolean get() = zygiskFolder.exists() | ||||
|     val zygiskUnloaded: Boolean get() = unloaded.exists() | ||||
|     val hasAction: Boolean; | ||||
|     private val removeFile = base.getChildFile("remove") | ||||
|     private val disableFile = base.getChildFile("disable") | ||||
|     private val updateFile = base.getChildFile("update") | ||||
|     val zygiskFolder = base.getChildFile("zygisk") | ||||
|  | ||||
|     val updated get() = updateFile.exists() | ||||
|     val isRiru = (id == "riru-core") || base.getChildFile("riru").exists() | ||||
|     val isZygisk = zygiskFolder.exists() | ||||
|     val zygiskUnloaded = zygiskFolder.getChildFile("unloaded").exists() | ||||
|     val hasAction = base.getChildFile("action.sh").exists() | ||||
|  | ||||
|     var enable: Boolean | ||||
|         get() = !disableFile.exists() | ||||
| @@ -90,19 +89,16 @@ data class LocalModule( | ||||
|  | ||||
|     init { | ||||
|         runCatching { | ||||
|             parseProps(Shell.cmd("dos2unix < $path/module.prop").exec().out) | ||||
|             parseProps(Shell.cmd("dos2unix < $base/module.prop").exec().out) | ||||
|         } | ||||
|  | ||||
|         if (id.isEmpty()) { | ||||
|             val sep = path.lastIndexOf('/') | ||||
|             id = path.substring(sep + 1) | ||||
|             id = base.name | ||||
|         } | ||||
|  | ||||
|         if (name.isEmpty()) { | ||||
|             name = id | ||||
|         } | ||||
|  | ||||
|         hasAction = RootUtils.fs.getFile(path, "action.sh").exists() | ||||
|     } | ||||
|  | ||||
|     suspend fun fetch(): Boolean { | ||||
| @@ -125,14 +121,14 @@ data class LocalModule( | ||||
|  | ||||
|     companion object { | ||||
|  | ||||
|         fun loaded() = RootUtils.fs.getFile(Const.MAGISK_PATH).exists() | ||||
|         fun loaded() = RootUtils.fs.getFile(Const.MODULE_PATH).exists() | ||||
|  | ||||
|         suspend fun installed() = withContext(Dispatchers.IO) { | ||||
|             RootUtils.fs.getFile(Const.MAGISK_PATH) | ||||
|             RootUtils.fs.getFile(Const.MODULE_PATH) | ||||
|                 .listFiles() | ||||
|                 .orEmpty() | ||||
|                 .filter { !it.isFile && !it.isHidden } | ||||
|                 .map { LocalModule("${Const.MAGISK_PATH}/${it.name}") } | ||||
|                 .map { LocalModule(it) } | ||||
|                 .sortedBy { it.name.lowercase(Locale.ROOT) } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.nio.ByteBuffer; | ||||
|  | ||||
| public class ByteArrayStream extends ByteArrayOutputStream { | ||||
|  | ||||
| @@ -27,4 +28,8 @@ public class ByteArrayStream extends ByteArrayOutputStream { | ||||
|     public ByteArrayInputStream getInputStream() { | ||||
|         return new ByteArrayInputStream(buf, 0, count); | ||||
|     } | ||||
|  | ||||
|     public ByteBuffer toByteBuffer() { | ||||
|         return ByteBuffer.wrap(buf, 0, count); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -510,7 +510,7 @@ public class SignApk { | ||||
|         privateKey[0] = key; | ||||
|  | ||||
|         // Generate, in memory, an APK signed using standard JAR Signature Scheme. | ||||
|         ByteArrayOutputStream v1SignedApkBuf = new ByteArrayOutputStream(); | ||||
|         ByteArrayStream v1SignedApkBuf = new ByteArrayStream(); | ||||
|         JarOutputStream outputJar = new JarOutputStream(v1SignedApkBuf); | ||||
|         // Use maximum compression for compressed entries because the APK lives forever on | ||||
|         // the system partition. | ||||
| @@ -519,8 +519,7 @@ public class SignApk { | ||||
|         copyFiles(manifest, inputJar, outputJar, timestamp, alignment); | ||||
|         signFile(manifest, publicKey, privateKey, timestamp, outputJar); | ||||
|         outputJar.close(); | ||||
|         ByteBuffer v1SignedApk = ByteBuffer.wrap(v1SignedApkBuf.toByteArray()); | ||||
|         v1SignedApkBuf.reset(); | ||||
|         ByteBuffer v1SignedApk = v1SignedApkBuf.toByteBuffer(); | ||||
|  | ||||
|         ByteBuffer[] outputChunks; | ||||
|         List<ApkSignerV2.SignerConfig> signerConfigs = createV2SignerConfigs(privateKey, publicKey, | ||||
|   | ||||
| @@ -17,7 +17,6 @@ import com.topjohnwu.magisk.core.Info | ||||
| import com.topjohnwu.magisk.core.di.ServiceLocator | ||||
| import com.topjohnwu.magisk.core.isRunningAsStub | ||||
| import com.topjohnwu.magisk.core.ktx.copyAll | ||||
| import com.topjohnwu.magisk.core.ktx.copyAndClose | ||||
| import com.topjohnwu.magisk.core.ktx.writeTo | ||||
| import com.topjohnwu.magisk.core.utils.DummyList | ||||
| import com.topjohnwu.magisk.core.utils.MediaStoreUtils | ||||
| @@ -47,7 +46,6 @@ import java.io.OutputStream | ||||
| import java.io.PushbackInputStream | ||||
| import java.nio.ByteBuffer | ||||
| import java.security.SecureRandom | ||||
| import java.util.Arrays | ||||
| import java.util.Locale | ||||
| import java.util.concurrent.atomic.AtomicBoolean | ||||
|  | ||||
| @@ -134,7 +132,6 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|                         if (entry != null) { | ||||
|                             val magisk32 = File(installDir, "magisk32") | ||||
|                             zf.getInputStream(entry).writeTo(magisk32) | ||||
|                             magisk32.setExecutable(true) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| @@ -149,11 +146,15 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|                     Os.symlink(lib.path, "$installDir/$name") | ||||
|                 } | ||||
|  | ||||
|                 // Also symlink magisk32 on 64-bit devices that supports 32-bit | ||||
|                 val lib32 = info.javaClass.getDeclaredField("secondaryNativeLibraryDir") | ||||
|                     .get(info) as String? | ||||
|                 if (lib32 != null) { | ||||
|                     Os.symlink("$lib32/libmagisk.so", "$installDir/magisk32"); | ||||
|                 // Also extract magisk32 on 64-bit devices that supports 32-bit | ||||
|                 val abi32 = Const.CPU_ABI_32 | ||||
|                 if (Process.is64Bit() && abi32 != null) { | ||||
|                     val name = "lib/$abi32/libmagisk.so" | ||||
|                     val entry = javaClass.classLoader!!.getResourceAsStream(name) | ||||
|                     if (entry != null) { | ||||
|                         val magisk32 = File(installDir, "magisk32") | ||||
|                         entry.writeTo(magisk32) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @@ -191,7 +192,8 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|         return true | ||||
|     } | ||||
|  | ||||
|     private suspend fun InputStream.copyAndCloseOut(out: OutputStream) = out.use { copyAll(it) } | ||||
|     private suspend fun InputStream.copyAndCloseOut(out: OutputStream) = | ||||
|         out.use { copyAll(it, 1024 * 1024) } | ||||
|  | ||||
|     private class NoAvailableStream(s: InputStream) : FilterInputStream(s) { | ||||
|         // Make sure available is never called on the actual stream and always return 0 | ||||
| @@ -225,8 +227,8 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|         console.add("- Processing tar file") | ||||
|         var entry: TarArchiveEntry? = tarIn.nextEntry | ||||
|  | ||||
|         fun TarArchiveEntry.decompressedStream(): InputStream { | ||||
|             val stream = if (name.endsWith(".lz4")) | ||||
|         fun decompressedStream(): InputStream { | ||||
|             val stream = if (tarIn.currentEntry.name.endsWith(".lz4")) | ||||
|                 FramedLZ4CompressorInputStream(tarIn, true) else tarIn | ||||
|             return NoAvailableStream(stream) | ||||
|         } | ||||
| @@ -252,9 +254,9 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|  | ||||
|             if (bootItem != null) { | ||||
|                 console.add("-- Extracting: ${bootItem.name}") | ||||
|                 entry.decompressedStream().copyAndCloseOut(bootItem.file.newOutputStream()) | ||||
|                 decompressedStream().copyAndCloseOut(bootItem.file.newOutputStream()) | ||||
|             } else if (entry.name.contains("vbmeta.img")) { | ||||
|                 val rawData = entry.decompressedStream().readBytes() | ||||
|                 val rawData = decompressedStream().readBytes() | ||||
|                 // Valid vbmeta.img should be at least 256 bytes | ||||
|                 if (rawData.size < 256) | ||||
|                     continue | ||||
| @@ -287,7 +289,7 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|             } else { | ||||
|                 console.add("-- Copying   : ${entry.name}") | ||||
|                 tarOut.putArchiveEntry(entry) | ||||
|                 tarIn.copyAll(tarOut, bufferSize = 1024 * 1024) | ||||
|                 tarIn.copyAll(tarOut) | ||||
|                 tarOut.closeArchiveEntry() | ||||
|             } | ||||
|             entry = tarIn.nextEntry ?: break | ||||
| @@ -429,7 +431,7 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|  | ||||
|         // Process input file | ||||
|         try { | ||||
|             PushbackInputStream(uri.inputStream(), 512).use { src -> | ||||
|             PushbackInputStream(uri.inputStream().buffered(1024 * 1024), 512).use { src -> | ||||
|                 val head = ByteArray(512) | ||||
|                 if (src.read(head) != head.size) { | ||||
|                     console.add("! Invalid input file") | ||||
| @@ -438,12 +440,13 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|                 src.unread(head) | ||||
|  | ||||
|                 val magic = head.copyOf(4) | ||||
|                 val tarMagic = Arrays.copyOfRange(head, 257, 262) | ||||
|                 val tarMagic = head.copyOfRange(257, 262) | ||||
|  | ||||
|                 srcBoot = if (tarMagic.contentEquals("ustar".toByteArray())) { | ||||
|                     // tar file | ||||
|                     outFile = MediaStoreUtils.getFile("$destName.tar") | ||||
|                     outStream = TarArchiveOutputStream(outFile.uri.outputStream()).also { | ||||
|                     val os = outFile.uri.outputStream().buffered(1024 * 1024) | ||||
|                     outStream = TarArchiveOutputStream(os).also { | ||||
|                         it.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_STAR) | ||||
|                         it.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU) | ||||
|                     } | ||||
| @@ -500,7 +503,7 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|                 bootItem.file = newBoot | ||||
|                 bootItem.copyTo(outStream as TarArchiveOutputStream) | ||||
|             } else { | ||||
|                 newBoot.newInputStream().copyAndClose(outStream) | ||||
|                 newBoot.newInputStream().use { it.copyAll(outStream, 1024 * 1024) } | ||||
|             } | ||||
|             newBoot.delete() | ||||
|  | ||||
| @@ -514,6 +517,8 @@ abstract class MagiskInstallImpl protected constructor( | ||||
|             outFile.delete() | ||||
|             Timber.e(e) | ||||
|             return false | ||||
|         } finally { | ||||
|             outStream.close() | ||||
|         } | ||||
|  | ||||
|         // Fix up binaries | ||||
|   | ||||
| @@ -1,50 +0,0 @@ | ||||
| package com.topjohnwu.magisk.core.utils | ||||
|  | ||||
| import com.topjohnwu.magisk.core.ktx.copyAll | ||||
| import org.apache.commons.compress.archivers.zip.ZipArchiveEntry | ||||
| import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream | ||||
| import org.apache.commons.compress.archivers.zip.ZipFile | ||||
| import java.io.File | ||||
| import java.io.IOException | ||||
| import java.io.InputStream | ||||
|  | ||||
| @Throws(IOException::class) | ||||
| suspend fun File.unzip(folder: File, path: String = "", junkPath: Boolean = false) { | ||||
|     ZipFile.Builder().setFile(this).get().use { zip -> | ||||
|         for (entry in zip.entries) { | ||||
|             if (!entry.name.startsWith(path) || entry.isDirectory) { | ||||
|                 // Ignore directories, only create files | ||||
|                 continue | ||||
|             } | ||||
|             val name = if (junkPath) | ||||
|                 entry.name.substring(entry.name.lastIndexOf('/') + 1) | ||||
|             else | ||||
|                 entry.name | ||||
|             val dest = File(folder, name) | ||||
|             dest.parentFile?.mkdirs() | ||||
|             dest.outputStream().use { out -> zip.getInputStream(entry).copyAll(out) } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Throws(IOException::class) | ||||
| suspend fun InputStream.unzip(folder: File, path: String = "", junkPath: Boolean = false) { | ||||
|     ZipArchiveInputStream(this).use { zin -> | ||||
|         var entry: ZipArchiveEntry | ||||
|         while (true) { | ||||
|             entry = zin.nextEntry ?: break | ||||
|             if (!entry.name.startsWith(path) || entry.isDirectory) { | ||||
|                 // Ignore directories, only create files | ||||
|                 continue | ||||
|             } | ||||
|             val name = if (junkPath) | ||||
|                 entry.name.substring(entry.name.lastIndexOf('/') + 1) | ||||
|             else | ||||
|                 entry.name | ||||
|  | ||||
|             val dest = File(folder, name) | ||||
|             dest.parentFile?.mkdirs() | ||||
|             dest.outputStream().use { out -> zin.copyAll(out) } | ||||
|         } | ||||
|     } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user