From db4aa3b519349abfd6d30678e67a849ec0a359be Mon Sep 17 00:00:00 2001 From: Chirayu Desai <chirayudesai1@gmail.com> Date: Tue, 18 Apr 2017 23:05:21 +0530 Subject: [PATCH 1/3] Installer: Use content URI on API >= 24 for DefaultInstaller fallback * When there's a permission mismatch (#951, #890), the fallback DefaultInstaller is invoked, which enforces file and content schemes for API < 24 and >= 24 respectively. * Use content URI in that case, which allows the fallback to work. --- .../fdroid/fdroid/installer/Installer.java | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) 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 0b72bf157..e77b83634 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; +import android.os.Build; import android.os.PatternMatcher; import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; @@ -228,6 +229,19 @@ public abstract class Installer { * installation of that specific APK */ public void installPackage(Uri localApkUri, Uri downloadUri) { + Uri sanitizedUri; + + try { + // move apk file to private directory for installation and check hash + sanitizedUri = ApkFileProvider.getSafeUri( + context, localApkUri, apk, supportsContentUri()); + } catch (IOException e) { + Log.e(TAG, e.getMessage(), e); + sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, + e.getMessage()); + return; + } + try { // verify that permissions of the apk file match the ones from the apk object ApkVerifier apkVerifier = new ApkVerifier(context, localApkUri, apk); @@ -245,23 +259,18 @@ public abstract class Installer { Log.e(TAG, e.getMessage(), e); Log.e(TAG, "Falling back to AOSP DefaultInstaller!"); DefaultInstaller defaultInstaller = new DefaultInstaller(context, apk); - defaultInstaller.installPackageInternal(localApkUri, downloadUri); + // https://code.google.com/p/android/issues/detail?id=205827 + if (Build.VERSION.SDK_INT >= 24) { + // content scheme for N and above + defaultInstaller.installPackageInternal(sanitizedUri, downloadUri); + } else { + // file scheme for below N + defaultInstaller.installPackageInternal(localApkUri, downloadUri); + } return; } } - Uri sanitizedUri; - try { - // move apk file to private directory for installation and check hash - sanitizedUri = ApkFileProvider.getSafeUri( - context, localApkUri, apk, supportsContentUri()); - } catch (IOException e) { - Log.e(TAG, e.getMessage(), e); - sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, - e.getMessage()); - return; - } - installPackageInternal(sanitizedUri, downloadUri); } From 432f45254b569125446d6d69507b134c4e85e56b Mon Sep 17 00:00:00 2001 From: Chirayu Desai <chirayudesai1@gmail.com> Date: Tue, 18 Apr 2017 23:49:16 +0530 Subject: [PATCH 2/3] PrivilegedInstaller: fallback to default installer for uninstall * On API >= 24, in cases when the installer package name is not set to privext, the system won't let us uninstall. * Fallback to the DefaultInstaller so that uninstall still works. --- .../fdroid/fdroid/compat/PackageManagerCompat.java | 2 ++ .../fdroid/installer/InstallManagerService.java | 6 +++++- .../java/org/fdroid/fdroid/installer/Installer.java | 12 ++++++++++++ .../fdroid/fdroid/installer/PrivilegedInstaller.java | 5 +---- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/compat/PackageManagerCompat.java b/app/src/main/java/org/fdroid/fdroid/compat/PackageManagerCompat.java index 0daf49d6b..9c625c4ac 100644 --- a/app/src/main/java/org/fdroid/fdroid/compat/PackageManagerCompat.java +++ b/app/src/main/java/org/fdroid/fdroid/compat/PackageManagerCompat.java @@ -29,6 +29,8 @@ public class PackageManagerCompat { mPm.setInstallerPackageName(packageName, "org.fdroid.fdroid"); } Utils.debugLog(TAG, "Installer package name for " + packageName + " set successfully"); + } catch (SecurityException e) { + throw new SecurityException(e); } catch (Exception e) { // Many problems can occur: // * App wasn't installed due to incompatibility diff --git a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java index e36d21f4c..1237d5181 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java @@ -338,7 +338,11 @@ public class InstallManagerService extends Service { Apk apkComplete = appUpdateStatusManager.getApk(downloadUrl); if (apkComplete != null) { - PackageManagerCompat.setInstaller(context, getPackageManager(), apkComplete.packageName); + try { + PackageManagerCompat.setInstaller(context, getPackageManager(), apkComplete.packageName); + } catch (SecurityException e) { + // Will happen if we fell back to DefaultInstaller for some reason. + } } localBroadcastManager.unregisterReceiver(this); break; 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 e77b83634..7bf061005 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java @@ -31,6 +31,8 @@ import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.Log; +import org.fdroid.fdroid.Utils; +import org.fdroid.fdroid.compat.PackageManagerCompat; import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.ApkProvider; import org.fdroid.fdroid.privileged.views.AppDiff; @@ -138,6 +140,16 @@ public abstract class Installer { return null; } + try { + PackageManagerCompat.setInstaller(context, context.getPackageManager(), apk.packageName); + } catch (SecurityException e) { + Utils.debugLog(TAG, "Falling back to default installer for uninstall"); + Intent intent = new Intent(context, DefaultInstallerActivity.class); + intent.setAction(DefaultInstallerActivity.ACTION_UNINSTALL_PACKAGE); + intent.putExtra(Installer.EXTRA_APK, apk); + return intent; + } + Intent intent = new Intent(context, UninstallDialogActivity.class); intent.putExtra(Installer.EXTRA_APK, apk); diff --git a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java index e0e9a8623..719b64288 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java @@ -34,6 +34,7 @@ import android.util.Log; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.compat.PackageManagerCompat; import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.privileged.IPrivilegedCallback; @@ -395,10 +396,6 @@ public class PrivilegedInstaller extends Installer { } }; - /* - * Set installer to the privileged extension - */ - PackageManagerCompat.setInstaller(context, context.getPackageManager(), apk.packageName); Intent serviceIntent = new Intent(PRIVILEGED_EXTENSION_SERVICE_INTENT); serviceIntent.setPackage(PRIVILEGED_EXTENSION_PACKAGE_NAME); context.getApplicationContext().bindService(serviceIntent, mServiceConnection, From 06dff8184bdd585343e6a62f88aa51745d1471c0 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner <hans@eds.org> Date: Tue, 18 Apr 2017 21:07:16 +0200 Subject: [PATCH 3/3] no need to catch an exception, only to throw it Just let the SecurityException be throwing where it originated. From PMD: "A catch statement that catches an exception only to wrap it in a new instance of the same type of exception and throw it should be avoided". This cleans up a little from !482. Ctrl-Alt-L and Ctrl-Alt-O before committing! :-) --- .../java/org/fdroid/fdroid/compat/PackageManagerCompat.java | 5 +---- .../org/fdroid/fdroid/installer/PrivilegedInstaller.java | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/compat/PackageManagerCompat.java b/app/src/main/java/org/fdroid/fdroid/compat/PackageManagerCompat.java index 9c625c4ac..7c02411cc 100644 --- a/app/src/main/java/org/fdroid/fdroid/compat/PackageManagerCompat.java +++ b/app/src/main/java/org/fdroid/fdroid/compat/PackageManagerCompat.java @@ -5,9 +5,8 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; import android.util.Log; - -import org.fdroid.fdroid.installer.PrivilegedInstaller; import org.fdroid.fdroid.Utils; +import org.fdroid.fdroid.installer.PrivilegedInstaller; public class PackageManagerCompat { @@ -29,8 +28,6 @@ public class PackageManagerCompat { mPm.setInstallerPackageName(packageName, "org.fdroid.fdroid"); } Utils.debugLog(TAG, "Installer package name for " + packageName + " set successfully"); - } catch (SecurityException e) { - throw new SecurityException(e); } catch (Exception e) { // Many problems can occur: // * App wasn't installed due to incompatibility diff --git a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java index 719b64288..93b077ec9 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java @@ -31,11 +31,8 @@ import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; - import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; -import org.fdroid.fdroid.Utils; -import org.fdroid.fdroid.compat.PackageManagerCompat; import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.privileged.IPrivilegedCallback; import org.fdroid.fdroid.privileged.IPrivilegedService;