perf: Do not load patches twice (#1328)

This commit is contained in:
oSumAtrIX 2023-10-04 21:58:25 +02:00 committed by GitHub
commit a709abd80c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 82 deletions

View file

@ -85,7 +85,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// ReVanced // ReVanced
implementation "app.revanced:revanced-patcher:15.0.3" implementation "app.revanced:revanced-patcher:16.0.0"
// Signing & aligning // Signing & aligning
implementation("org.bouncycastle:bcpkix-jdk15on:1.70") implementation("org.bouncycastle:bcpkix-jdk15on:1.70")

View file

@ -8,6 +8,7 @@ import app.revanced.manager.flutter.utils.signing.Signer
import app.revanced.manager.flutter.utils.zip.ZipFile import app.revanced.manager.flutter.utils.zip.ZipFile
import app.revanced.manager.flutter.utils.zip.structures.ZipEntry import app.revanced.manager.flutter.utils.zip.structures.ZipEntry
import app.revanced.patcher.PatchBundleLoader import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.PatchSet
import app.revanced.patcher.Patcher import app.revanced.patcher.Patcher
import app.revanced.patcher.PatcherOptions import app.revanced.patcher.PatcherOptions
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
@ -31,6 +32,8 @@ class MainActivity : FlutterActivity() {
private var cancel: Boolean = false private var cancel: Boolean = false
private var stopResult: MethodChannel.Result? = null private var stopResult: MethodChannel.Result? = null
private lateinit var patches: PatchSet
override fun configureFlutterEngine(flutterEngine: FlutterEngine) { override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine) super.configureFlutterEngine(flutterEngine)
@ -46,7 +49,6 @@ class MainActivity : FlutterActivity() {
mainChannel.setMethodCallHandler { call, result -> mainChannel.setMethodCallHandler { call, result ->
when (call.method) { when (call.method) {
"runPatcher" -> { "runPatcher" -> {
val patchBundleFilePath = call.argument<String>("patchBundleFilePath")
val originalFilePath = call.argument<String>("originalFilePath") val originalFilePath = call.argument<String>("originalFilePath")
val inputFilePath = call.argument<String>("inputFilePath") val inputFilePath = call.argument<String>("inputFilePath")
val patchedFilePath = call.argument<String>("patchedFilePath") val patchedFilePath = call.argument<String>("patchedFilePath")
@ -57,7 +59,7 @@ class MainActivity : FlutterActivity() {
val keyStoreFilePath = call.argument<String>("keyStoreFilePath") val keyStoreFilePath = call.argument<String>("keyStoreFilePath")
val keystorePassword = call.argument<String>("keystorePassword") val keystorePassword = call.argument<String>("keystorePassword")
if (patchBundleFilePath != null && if (
originalFilePath != null && originalFilePath != null &&
inputFilePath != null && inputFilePath != null &&
patchedFilePath != null && patchedFilePath != null &&
@ -71,7 +73,6 @@ class MainActivity : FlutterActivity() {
cancel = false cancel = false
runPatcher( runPatcher(
result, result,
patchBundleFilePath,
originalFilePath, originalFilePath,
inputFilePath, inputFilePath,
patchedFilePath, patchedFilePath,
@ -94,17 +95,19 @@ class MainActivity : FlutterActivity() {
val patchBundleFilePath = call.argument<String>("patchBundleFilePath")!! val patchBundleFilePath = call.argument<String>("patchBundleFilePath")!!
val cacheDirPath = call.argument<String>("cacheDirPath")!! val cacheDirPath = call.argument<String>("cacheDirPath")!!
try {
patches = PatchBundleLoader.Dex(
File(patchBundleFilePath),
optimizedDexDirectory = File(cacheDirPath)
)
} catch (ex: Exception) {
return@setMethodCallHandler result.notImplemented()
} catch (err: Error) {
return@setMethodCallHandler result.notImplemented()
}
JSONArray().apply { JSONArray().apply {
try { patches.forEach {
PatchBundleLoader.Dex(
File(patchBundleFilePath),
optimizedDexDirectory = File(cacheDirPath)
)
} catch (ex: Exception) {
return@setMethodCallHandler result.notImplemented()
} catch (err: Error) {
return@setMethodCallHandler result.notImplemented()
}.forEach {
JSONObject().apply { JSONObject().apply {
put("name", it.name) put("name", it.name)
put("description", it.description) put("description", it.description)
@ -136,7 +139,6 @@ class MainActivity : FlutterActivity() {
private fun runPatcher( private fun runPatcher(
result: MethodChannel.Result, result: MethodChannel.Result,
patchBundleFilePath: String,
originalFilePath: String, originalFilePath: String,
inputFilePath: String, inputFilePath: String,
patchedFilePath: String, patchedFilePath: String,
@ -223,10 +225,7 @@ class MainActivity : FlutterActivity() {
updateProgress(0.1, "Loading patches...", "Loading patches") updateProgress(0.1, "Loading patches...", "Loading patches")
val patches = PatchBundleLoader.Dex( val patches = patches.filter { patch ->
File(patchBundleFilePath),
optimizedDexDirectory = cacheDir
).filter { patch ->
val isCompatible = patch.compatiblePackages?.any { val isCompatible = patch.compatiblePackages?.any {
it.name == patcher.context.packageMetadata.packageName it.name == patcher.context.packageMetadata.packageName
} ?: false } ?: false
@ -331,7 +330,7 @@ class MainActivity : FlutterActivity() {
val stack = ex.stackTraceToString() val stack = ex.stackTraceToString()
updateProgress( updateProgress(
-100.0, -100.0,
"Aborted", "Failed",
"An error occurred:\n$stack" "An error occurred:\n$stack"
) )
} }

View file

@ -31,7 +31,7 @@ class PatcherAPI {
File? outFile; File? outFile;
Future<void> initialize() async { Future<void> initialize() async {
await _loadPatches(); await loadPatches();
await _managerAPI.downloadIntegrations(); await _managerAPI.downloadIntegrations();
final Directory appCache = await getTemporaryDirectory(); final Directory appCache = await getTemporaryDirectory();
_dataDir = await getExternalStorageDirectory() ?? appCache; _dataDir = await getExternalStorageDirectory() ?? appCache;
@ -59,12 +59,10 @@ class PatcherAPI {
} }
List<Patch> getUniversalPatches() { List<Patch> getUniversalPatches() {
return _patches return _patches.where((patch) => patch.compatiblePackages.isEmpty).toList();
.where((patch) => patch.compatiblePackages.isEmpty)
.toList();
} }
Future<void> _loadPatches() async { Future<void> loadPatches() async {
try { try {
if (_patches.isEmpty) { if (_patches.isEmpty) {
_patches = await _managerAPI.getPatches(); _patches = await _managerAPI.getPatches();
@ -85,15 +83,14 @@ class PatcherAPI {
) async { ) async {
final List<ApplicationWithIcon> filteredApps = []; final List<ApplicationWithIcon> filteredApps = [];
final bool allAppsIncluded = final bool allAppsIncluded =
_universalPatches.isNotEmpty && _universalPatches.isNotEmpty && showUniversalPatches;
showUniversalPatches;
if (allAppsIncluded) { if (allAppsIncluded) {
final appList = await DeviceApps.getInstalledApplications( final appList = await DeviceApps.getInstalledApplications(
includeAppIcons: true, includeAppIcons: true,
onlyAppsWithLaunchIntent: true, onlyAppsWithLaunchIntent: true,
); );
for(final app in appList) { for (final app in appList) {
filteredApps.add(app as ApplicationWithIcon); filteredApps.add(app as ApplicationWithIcon);
} }
} }
@ -154,9 +151,9 @@ class PatcherAPI {
String apkFilePath, String apkFilePath,
List<Patch> selectedPatches, List<Patch> selectedPatches,
) async { ) async {
final File? patchBundleFile = await _managerAPI.downloadPatches();
final File? integrationsFile = await _managerAPI.downloadIntegrations(); final File? integrationsFile = await _managerAPI.downloadIntegrations();
if (patchBundleFile != null) {
if (integrationsFile != null) {
_dataDir.createSync(); _dataDir.createSync();
_tmpDir.createSync(); _tmpDir.createSync();
final Directory workDir = _tmpDir.createTempSync('tmp-'); final Directory workDir = _tmpDir.createTempSync('tmp-');
@ -170,12 +167,11 @@ class PatcherAPI {
await patcherChannel.invokeMethod( await patcherChannel.invokeMethod(
'runPatcher', 'runPatcher',
{ {
'patchBundleFilePath': patchBundleFile.path,
'originalFilePath': originalFilePath, 'originalFilePath': originalFilePath,
'inputFilePath': inputFile.path, 'inputFilePath': inputFile.path,
'patchedFilePath': patchedFile.path, 'patchedFilePath': patchedFile.path,
'outFilePath': outFile!.path, 'outFilePath': outFile!.path,
'integrationsPath': integrationsFile!.path, 'integrationsPath': integrationsFile.path,
'selectedPatches': selectedPatches.map((p) => p.name).toList(), 'selectedPatches': selectedPatches.map((p) => p.name).toList(),
'cacheDirPath': cacheDir.path, 'cacheDirPath': cacheDir.path,
'keyStoreFilePath': _keyStoreFile.path, 'keyStoreFilePath': _keyStoreFile.path,

View file

@ -130,28 +130,28 @@ class InstallerViewModel extends BaseViewModel {
Future<void> runPatcher() async { Future<void> runPatcher() async {
try { try {
update(0.0, 'Initializing...', 'Initializing installer'); await _patcherAPI.runPatcher(
if (_patches.isNotEmpty) { _app.packageName,
try { _app.apkFilePath,
update(0.1, '', 'Creating working directory'); _patches,
await _patcherAPI.runPatcher( );
_app.packageName, } on Exception catch (e) {
_app.apkFilePath, update(
_patches, -100.0,
); 'Failed...',
} on Exception catch (e) { 'Something went wrong:\n$e',
update( );
-100.0, if (kDebugMode) {
'Aborted...', print(e);
'An error occurred! Aborted\nError:\n$e',
);
if (kDebugMode) {
print(e);
}
}
} else {
update(-100.0, 'Aborted...', 'No app or patches selected! Aborted');
} }
}
// Necessary to reset the state of patches by reloading them
// in a later patching process.
_managerAPI.patches.clear();
await _patcherAPI.loadPatches();
try {
if (FlutterBackground.isBackgroundExecutionEnabled) { if (FlutterBackground.isBackgroundExecutionEnabled) {
try { try {
FlutterBackground.disableBackgroundExecution(); FlutterBackground.disableBackgroundExecution();
@ -209,7 +209,8 @@ class InstallerViewModel extends BaseViewModel {
), ),
RadioListTile( RadioListTile(
title: I18nText('installerView.installNonRootType'), title: I18nText('installerView.installNonRootType'),
contentPadding: const EdgeInsets.symmetric(horizontal: 16), contentPadding:
const EdgeInsets.symmetric(horizontal: 16),
value: 0, value: 0,
groupValue: value, groupValue: value,
onChanged: (selected) { onChanged: (selected) {
@ -218,7 +219,8 @@ class InstallerViewModel extends BaseViewModel {
), ),
RadioListTile( RadioListTile(
title: I18nText('installerView.installRootType'), title: I18nText('installerView.installRootType'),
contentPadding: const EdgeInsets.symmetric(horizontal: 16), contentPadding:
const EdgeInsets.symmetric(horizontal: 16),
value: 1, value: 1,
groupValue: value, groupValue: value,
onChanged: (selected) { onChanged: (selected) {
@ -256,9 +258,9 @@ class InstallerViewModel extends BaseViewModel {
Future<void> stopPatcher() async { Future<void> stopPatcher() async {
try { try {
isCanceled = true; isCanceled = true;
update(0.5, 'Aborting...', 'Canceling patching process'); update(0.5, 'Canceling...', 'Canceling patching process');
await _patcherAPI.stopPatcher(); await _patcherAPI.stopPatcher();
update(-100.0, 'Aborted...', 'Press back to exit'); update(-100.0, 'Canceled...', 'Press back to exit');
} on Exception catch (e) { } on Exception catch (e) {
if (kDebugMode) { if (kDebugMode) {
print(e); print(e);
@ -269,33 +271,34 @@ class InstallerViewModel extends BaseViewModel {
Future<void> installResult(BuildContext context, bool installAsRoot) async { Future<void> installResult(BuildContext context, bool installAsRoot) async {
try { try {
_app.isRooted = installAsRoot; _app.isRooted = installAsRoot;
update( update(
1.0, 1.0,
'Installing...', 'Installing...',
_app.isRooted _app.isRooted
? 'Installing patched file using root method' ? 'Installing patched file using root method'
: 'Installing patched file using nonroot method', : 'Installing patched file using nonroot method',
); );
isInstalled = await _patcherAPI.installPatchedFile(_app); isInstalled = await _patcherAPI.installPatchedFile(_app);
if (isInstalled) { if (isInstalled) {
_app.isFromStorage = false; _app.isFromStorage = false;
_app.patchDate = DateTime.now(); _app.patchDate = DateTime.now();
_app.appliedPatches = _patches.map((p) => p.name).toList(); _app.appliedPatches = _patches.map((p) => p.name).toList();
// In case a patch changed the app name or package name, // In case a patch changed the app name or package name,
// update the app info. // update the app info.
final app = await DeviceApps.getAppFromStorage(_patcherAPI.outFile!.path); final app =
if (app != null) { await DeviceApps.getAppFromStorage(_patcherAPI.outFile!.path);
_app.name = app.appName; if (app != null) {
_app.packageName = app.packageName; _app.name = app.appName;
} _app.packageName = app.packageName;
await _managerAPI.savePatchedApp(_app);
update(1.0, 'Installed!', 'Installed!');
} else {
// TODO(aabed): Show error message.
} }
await _managerAPI.savePatchedApp(_app);
update(1.0, 'Installed!', 'Installed!');
} else {
// TODO(aabed): Show error message.
}
} on Exception catch (e) { } on Exception catch (e) {
if (kDebugMode) { if (kDebugMode) {
print(e); print(e);