Skip to content

Commit

Permalink
[APK] Prevent crashing due to forceDexOpt failing in Android 12
Browse files Browse the repository at this point in the history
In Android 12, forceDexOpt always fails due to a bug in the Android framework:

#1131

As a workaround, the optimisation is done via performDexOptMode imitating
whatever forceDexOpt does.

Signed-off-by: Muntashir Al-Islam <[email protected]>
  • Loading branch information
MuntashirAkon committed Sep 8, 2023
1 parent cc9304a commit a82016f
Showing 1 changed file with 22 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import java.util.Objects;

import io.github.muntashirakon.AppManager.self.SelfPermissions;

@RequiresApi(Build.VERSION_CODES.N)
Expand Down Expand Up @@ -81,15 +83,20 @@ public boolean forceDexOpt() {
try {
if (SelfPermissions.isSystemOrRoot()) {
// Allowed for only root/system
mPm.forceDexOpt(mPackageName);
} else {
// forceDexOpt only applies certain set of configurations with performDexOptMode. So, it's possible to
// do the same using performDexOptMode in unprivileged mode
// https://android.googlesource.com/platform/frameworks/base/+/eb4af72f526c8351ad22322a635507a54c9ad1b8/services/core/java/com/android/server/pm/DexOptHelper.java#495
return performDexOptMode(false, DexOptOptions.getDefaultCompilerFilter(), true, true, null);
try {
mPm.forceDexOpt(mPackageName);
return true;
} catch (IllegalArgumentException e) {
if (Objects.equals(e.getMessage(), "reason -1 invalid")) {
// AOSP bug: https://github.com/MuntashirAkon/AppManager/issues/1131
return forceDexOptUnprivileged();
}
// Other valid error
throw e;
}
}
return true;
} catch (RemoteException | SecurityException e) {
return forceDexOptUnprivileged();
} catch (RemoteException | SecurityException | IllegalArgumentException e) {
mLastError = e;
} catch (IllegalStateException e) {
String message = e.getMessage();
Expand All @@ -103,4 +110,11 @@ public boolean forceDexOpt() {
}
return false;
}

private boolean forceDexOptUnprivileged() {
// forceDexOpt only applies certain set of configurations with performDexOptMode. So, it's possible to
// do the same using performDexOptMode in unprivileged mode
// https://android.googlesource.com/platform/frameworks/base/+/eb4af72f526c8351ad22322a635507a54c9ad1b8/services/core/java/com/android/server/pm/DexOptHelper.java#495
return performDexOptMode(false, DexOptOptions.getDefaultCompilerFilter(), true, true, null);
}
}

0 comments on commit a82016f

Please sign in to comment.