From 6ef716b0e4ef711a9b1ed04d822143c705d9ad0e Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Wed, 14 Sep 2022 09:59:56 +0100 Subject: [PATCH] fix: One more fix to root installations management --- .../app/revanced/manager/MainActivity.kt | 27 +++--- lib/services/patcher_api.dart | 29 +++---- lib/services/root_api.dart | 87 +++++++++++++++---- .../views/installer/installer_viewmodel.dart | 7 +- 4 files changed, 101 insertions(+), 49 deletions(-) diff --git a/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt b/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt index 6d6d4df0..8025b46b 100644 --- a/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt +++ b/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt @@ -31,18 +31,9 @@ class MainActivity : FlutterActivity() { installerChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, INSTALLER_CHANNEL) mainChannel.setMethodCallHandler { call, result -> when (call.method) { - "copyOriginalApk" -> { - val originalFilePath = call.argument("originalFilePath") - val backupFilePath = call.argument("backupFilePath") - if (originalFilePath != null && backupFilePath != null) { - File(originalFilePath).copyTo(File(backupFilePath), true) - result.success(null) - } else { - result.notImplemented() - } - } "runPatcher" -> { val patchBundleFilePath = call.argument("patchBundleFilePath") + val originalFilePath = call.argument("originalFilePath") val inputFilePath = call.argument("inputFilePath") val patchedFilePath = call.argument("patchedFilePath") val outFilePath = call.argument("outFilePath") @@ -53,6 +44,7 @@ class MainActivity : FlutterActivity() { val resourcePatching = call.argument("resourcePatching") val keyStoreFilePath = call.argument("keyStoreFilePath") if (patchBundleFilePath != null && + originalFilePath != null && inputFilePath != null && patchedFilePath != null && outFilePath != null && @@ -66,6 +58,7 @@ class MainActivity : FlutterActivity() { runPatcher( result, patchBundleFilePath, + originalFilePath, inputFilePath, patchedFilePath, outFilePath, @@ -88,6 +81,7 @@ class MainActivity : FlutterActivity() { fun runPatcher( result: MethodChannel.Result, patchBundleFilePath: String, + originalFilePath: String, inputFilePath: String, patchedFilePath: String, outFilePath: String, @@ -98,6 +92,7 @@ class MainActivity : FlutterActivity() { resourcePatching: Boolean, keyStoreFilePath: String ) { + val originalFile = File(originalFilePath) val inputFile = File(inputFilePath) val patchedFile = File(patchedFilePath) val outFile = File(outFilePath) @@ -119,6 +114,18 @@ class MainActivity : FlutterActivity() { Thread( Runnable { + handler.post { + installerChannel.invokeMethod( + "update", + mapOf( + "progress" to 0.1, + "header" to "", + "log" to "Copying original apk" + ) + ) + } + originalFile.copyTo(inputFile, true) + handler.post { installerChannel.invokeMethod( "update", diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart index cd70656e..f9339301 100644 --- a/lib/services/patcher_api.dart +++ b/lib/services/patcher_api.dart @@ -82,31 +82,23 @@ class PatcherAPI { .toList(); } - Future copyOriginalApk( + Future getOriginalFilePath( String packageName, String originalFilePath, ) async { bool hasRootPermissions = await _rootAPI.hasRootPermissions(); if (hasRootPermissions) { - String originalRootPath = await _rootAPI.getOriginalFilePath(packageName); - if (File(originalRootPath).existsSync()) { - originalFilePath = originalRootPath; - } + originalFilePath = await _rootAPI.getOriginalFilePath( + packageName, + originalFilePath, + ); } - String backupFilePath = '${_tmpDir.path}/$packageName.apk'; - await patcherChannel.invokeMethod( - 'copyOriginalApk', - { - 'originalFilePath': originalFilePath, - 'backupFilePath': backupFilePath, - }, - ); - return backupFilePath; + return originalFilePath; } Future runPatcher( String packageName, - String inputFilePath, + String originalFilePath, List selectedPatches, ) async { bool mergeIntegrations = selectedPatches.any( @@ -140,6 +132,7 @@ class PatcherAPI { if (patchBundleFile != null) { _tmpDir.createSync(); Directory workDir = _tmpDir.createTempSync('tmp-'); + File inputFile = File('${workDir.path}/base.apk'); File patchedFile = File('${workDir.path}/patched.apk'); _outFile = File('${workDir.path}/out.apk'); Directory cacheDir = Directory('${workDir.path}/cache'); @@ -148,7 +141,11 @@ class PatcherAPI { 'runPatcher', { 'patchBundleFilePath': patchBundleFile.path, - 'inputFilePath': inputFilePath, + 'originalFilePath': await getOriginalFilePath( + packageName, + originalFilePath, + ), + 'inputFilePath': inputFile.path, 'patchedFilePath': patchedFile.path, 'outFilePath': _outFile!.path, 'integrationsPath': mergeIntegrations ? integrationsFile!.path : '', diff --git a/lib/services/root_api.dart b/lib/services/root_api.dart index 4f06ee3c..c4cfa80f 100644 --- a/lib/services/root_api.dart +++ b/lib/services/root_api.dart @@ -2,6 +2,7 @@ import 'package:root/root.dart'; class RootAPI { final String _managerDirPath = '/data/adb/revanced-manager'; + final String _managerTmpDirPath = '/data/local/tmp/revanced-manager'; final String _postFsDataDirPath = '/data/adb/post-fs-data.d'; final String _serviceDDirPath = '/data/adb/service.d'; @@ -10,6 +11,29 @@ class RootAPI { return isRooted != null && isRooted; } + Future setPermissions( + String permissions, + ownerGroup, + seLinux, + String filePath, + ) async { + if (permissions.isNotEmpty) { + await Root.exec( + cmd: 'chmod $permissions "$filePath"', + ); + } + if (ownerGroup.isNotEmpty) { + await Root.exec( + cmd: 'chown $ownerGroup "$filePath"', + ); + } + if (seLinux.isNotEmpty) { + await Root.exec( + cmd: 'chcon $seLinux "$filePath"', + ); + } + } + Future isAppInstalled(String packageName) async { if (packageName.isNotEmpty) { String? res = await Root.exec( @@ -76,6 +100,7 @@ class RootAPI { await Root.exec( cmd: 'mkdir -p "$_managerDirPath/$packageName"', ); + await setPermissions('0755', '', '', "$_managerDirPath/$packageName"); await saveOriginalFilePath(packageName, originalFilePath); await installServiceDScript(packageName); await installPostFsDataScript(packageName); @@ -97,9 +122,7 @@ class RootAPI { await Root.exec( cmd: 'echo \'$content\' > "$scriptFilePath"', ); - await Root.exec( - cmd: 'chmod 744 "$scriptFilePath"', - ); + await setPermissions('0744', '', '', scriptFilePath); } Future installPostFsDataScript(String packageName) async { @@ -110,9 +133,7 @@ class RootAPI { await Root.exec( cmd: 'echo \'$content\' > "$scriptFilePath"', ); - await Root.exec( - cmd: 'chmod 744 "$scriptFilePath"', - ); + await setPermissions('0744', '', '', scriptFilePath); } Future installApk(String packageName, String patchedFilePath) async { @@ -120,14 +141,11 @@ class RootAPI { await Root.exec( cmd: 'cp "$patchedFilePath" "$newPatchedFilePath"', ); - await Root.exec( - cmd: 'chmod 644 "$newPatchedFilePath"', - ); - await Root.exec( - cmd: 'chown system:system "$newPatchedFilePath"', - ); - await Root.exec( - cmd: 'chcon u:object_r:apk_data_file:s0 "$newPatchedFilePath"', + await setPermissions( + '0644', + 'system:system', + 'u:object_r:apk_data_file:s0', + newPatchedFilePath, ); } @@ -144,17 +162,52 @@ class RootAPI { ); } - Future getOriginalFilePath(String packageName) async { - return '$_managerDirPath/$packageName/original.apk'; + Future isMounted(String packageName) async { + String? res = await Root.exec( + cmd: 'cat /proc/mounts | grep $packageName', + ); + return res != null && res.isNotEmpty; + } + + Future getOriginalFilePath( + String packageName, + String originalFilePath, + ) async { + bool isInstalled = await isAppInstalled(packageName); + if (isInstalled && await isMounted(packageName)) { + originalFilePath = '$_managerTmpDirPath/$packageName/original.apk'; + await setPermissions( + '0644', + 'shell:shell', + 'u:object_r:apk_data_file:s0', + originalFilePath, + ); + } + return originalFilePath; } Future saveOriginalFilePath( String packageName, String originalFilePath, ) async { - String originalRootPath = '$_managerDirPath/$packageName/original.apk'; + String originalRootPath = '$_managerTmpDirPath/$packageName/original.apk'; + await Root.exec( + cmd: 'mkdir -p "$_managerTmpDirPath/$packageName"', + ); + await setPermissions( + '0755', + 'shell:shell', + '', + '$_managerTmpDirPath/$packageName', + ); await Root.exec( cmd: 'cp "$originalFilePath" "$originalRootPath"', ); + await setPermissions( + '0644', + 'shell:shell', + 'u:object_r:apk_data_file:s0', + originalFilePath, + ); } } diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index 393fea5e..8167dd0a 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -105,15 +105,10 @@ class InstallerViewModel extends BaseViewModel { update(0.0, 'Initializing...', 'Initializing installer'); if (_patches.isNotEmpty) { try { - update(0.1, '', 'Copying original apk'); - String inputFilePath = await _patcherAPI.copyOriginalApk( - _app.packageName, - _app.apkFilePath, - ); update(0.1, '', 'Creating working directory'); await _patcherAPI.runPatcher( _app.packageName, - inputFilePath, + _app.apkFilePath, _patches, ); } catch (e) {