diff --git a/app/src/main/java/org/fdroid/fdroid/installer/ApkVerifier.java b/app/src/main/java/org/fdroid/fdroid/installer/ApkVerifier.java index 5e40e3637..ebcd56b8d 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/ApkVerifier.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/ApkVerifier.java @@ -51,7 +51,7 @@ class ApkVerifier { this.pm = context.getPackageManager(); } - public void verifyApk() throws ApkVerificationException { + public void verifyApk() throws ApkVerificationException, ApkPermissionUnequalException { // parse downloaded apk file locally PackageInfo localApkInfo = pm.getPackageArchiveInfo( localApkUri.getPath(), PackageManager.GET_PERMISSIONS); @@ -78,9 +78,9 @@ class ApkVerifier { // Thus, containsAll() instead of equals() is used! // See also https://gitlab.com/fdroid/fdroidclient/issues/703 if (!expectedPermissions.containsAll(localPermissions)) { - throw new ApkVerificationException( + throw new ApkPermissionUnequalException( "Permissions of the apk file are not a true subset of the permissions listed by the repo," + - " i.e., some permissions have not been shown to the user!"); + " i.e., some permissions have not been shown to the user!"); } int localTargetSdkVersion = localApkInfo.applicationInfo.targetSdkVersion; @@ -93,7 +93,6 @@ class ApkVerifier { } else if (localTargetSdkVersion != expectedTargetSdkVersion) { throw new ApkVerificationException("TargetSdkVersion of apk file is not the expected targetSdkVersion!"); } - } private HashSet getLocalPermissionsSet(PackageInfo localApkInfo) { @@ -116,4 +115,15 @@ class ApkVerifier { } } + public static class ApkPermissionUnequalException extends Exception { + + ApkPermissionUnequalException(String message) { + super(message); + } + + ApkPermissionUnequalException(Throwable cause) { + super(cause); + } + } + } diff --git a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java index b6e6c4332..8df65cd4c 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java @@ -226,17 +226,35 @@ public abstract class Installer { * @param apk apk object of the app that should be installed */ public void installPackage(Uri localApkUri, Uri downloadUri, Apk apk) { - Uri sanitizedUri; try { // verify that permissions of the apk file match the ones from the apk object ApkVerifier apkVerifier = new ApkVerifier(context, localApkUri, apk); apkVerifier.verifyApk(); + } catch (ApkVerifier.ApkVerificationException e) { + Log.e(TAG, e.getMessage(), e); + sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, + e.getMessage()); + return; + } catch (ApkVerifier.ApkPermissionUnequalException e) { + // if permissions of apk are not the ones listed in the repo + // and an unattended installer is used, a wrong permission screen + // has been shown, thus fallback to AOSP DefaultInstaller! + if (isUnattended()) { + Log.e(TAG, e.getMessage(), e); + Log.e(TAG, "Falling back to AOSP DefaultInstaller!"); + DefaultInstaller defaultInstaller = new DefaultInstaller(context); + defaultInstaller.installPackageInternal(localApkUri, downloadUri, apk); + return; + } + } + Uri sanitizedUri; + try { // move apk file to private directory for installation and check hash sanitizedUri = ApkFileProvider.getSafeUri( context, localApkUri, apk, supportsContentUri()); - } catch (ApkVerifier.ApkVerificationException | IOException e) { - Log.e(TAG, "ApkVerifier / ApkFileProvider failed", e); + } catch (IOException e) { + Log.e(TAG, e.getMessage(), e); sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage()); return;