Use Uris more often instead of File

This commit is contained in:
Dominik Schürmann 2016-05-23 21:01:40 +03:00
parent a2356b05d6
commit bb273cd2f5
4 changed files with 24 additions and 43 deletions

View File

@ -4,6 +4,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.Utils;
@ -21,21 +22,17 @@ public class DefaultInstaller extends Installer {
@Override
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
Utils.debugLog(TAG, "ACTION_INSTALL uri: " + uri + " file: " + new File(uri.getPath()));
// TODO: rework for uri
File sanitizedFile = null;
Uri sanitizedUri;
try {
sanitizedFile = Installer.prepareApkFile(mContext, new File(uri.getPath()), packageName);
sanitizedUri = Installer.prepareApkFile(mContext, uri, packageName);
} catch (Installer.InstallFailedException e) {
e.printStackTrace();
Log.e(TAG, "prepareApkFile failed", e);
return;
}
Uri sanitizedUri = Uri.fromFile(sanitizedFile);
Utils.debugLog(TAG, "ACTION_INSTALL sanitizedUri: " + sanitizedUri);
Intent installIntent;
// special case: F-Droid Privileged Extension
@ -44,14 +41,13 @@ public class DefaultInstaller extends Installer {
// extension must be signed with the same public key as main F-Droid
// NOTE: Disabled for debug builds to be able to use official extension from repo
ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(mContext);
if (!BuildConfig.DEBUG && !signatureVerifier.hasFDroidSignature(sanitizedFile)) {
if (!BuildConfig.DEBUG && !signatureVerifier.hasFDroidSignature(new File(sanitizedUri.getPath()))) {
throw new RuntimeException("APK signature of extension not correct!");
}
installIntent = new Intent(mContext, InstallExtensionDialogActivity.class);
installIntent.setAction(InstallExtensionDialogActivity.ACTION_INSTALL);
installIntent.putExtra(InstallExtensionDialogActivity.EXTRA_INSTALL_APK,
sanitizedFile.getAbsolutePath());
installIntent.setData(sanitizedUri);
} else {
installIntent = new Intent(mContext, AndroidInstallerActivity.class);
installIntent.setAction(AndroidInstallerActivity.ACTION_INSTALL_PACKAGE);

View File

@ -37,7 +37,6 @@ import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.SanitizedFile;
import org.fdroid.fdroid.privileged.views.AppDiff;
import org.fdroid.fdroid.privileged.views.AppSecurityPermissions;
import org.fdroid.fdroid.privileged.views.InstallConfirmActivity;
import java.io.File;
import java.io.IOException;
@ -81,44 +80,28 @@ public abstract class Installer {
}
}
/**
* Callback from Installer. NOTE: This callback can be in a different thread
* than the UI thread
*/
// public interface InstallerCallback {
//
// int OPERATION_INSTALL = 1;
// int OPERATION_DELETE = 2;
//
// // Avoid using [-1,1] as they may conflict with Activity.RESULT_*
// int ERROR_CODE_CANCELED = 2;
// int ERROR_CODE_OTHER = 3;
// int ERROR_CODE_CANNOT_PARSE = 4;
//
// void onSuccess(int operation);
//
// void onError(int operation, int errorCode);
// }
Installer(Context context) {
this.mContext = context;
this.mPm = context.getPackageManager();
localBroadcastManager = LocalBroadcastManager.getInstance(context);
}
public static SanitizedFile prepareApkFile(Context context, File apkFile, String packageName)
public static Uri prepareApkFile(Context context, Uri uri, String packageName)
throws InstallFailedException {
SanitizedFile apkToInstall = null;
File apkFile = new File(uri.getPath());
SanitizedFile sanitizedApkFile = null;
try {
Map<String, Object> attributes = AndroidXMLDecompress.getManifestHeaderAttributes(apkFile.getAbsolutePath());
/* This isn't really needed, but might as well since we have the data already */
if (attributes.containsKey("packageName") && !TextUtils.equals(packageName, (String) attributes.get("packageName"))) {
throw new InstallFailedException(apkFile + " has packageName that clashes with " + packageName);
throw new InstallFailedException(uri + " has packageName that clashes with " + packageName);
}
if (!attributes.containsKey("versionCode")) {
throw new InstallFailedException(apkFile + " is missing versionCode!");
throw new InstallFailedException(uri + " is missing versionCode!");
}
int versionCode = (Integer) attributes.get("versionCode");
Apk apk = ApkProvider.Helper.find(context, packageName, versionCode, new String[]{
@ -129,10 +112,10 @@ public abstract class Installer {
* of the app to prevent attacks based on other apps swapping the file
* out during the install process. Most likely, apkFile was just downloaded,
* so it should still be in the RAM disk cache */
apkToInstall = SanitizedFile.knownSanitized(File.createTempFile("install-", ".apk",
sanitizedApkFile = SanitizedFile.knownSanitized(File.createTempFile("install-", ".apk",
context.getFilesDir()));
FileUtils.copyFile(apkFile, apkToInstall);
if (!verifyApkFile(apkToInstall, apk.hash, apk.hashType)) {
FileUtils.copyFile(apkFile, sanitizedApkFile);
if (!verifyApkFile(sanitizedApkFile, apk.hash, apk.hashType)) {
FileUtils.deleteQuietly(apkFile);
throw new InstallFailedException(apkFile + " failed to verify!");
}
@ -143,7 +126,7 @@ public abstract class Installer {
// have access is insecure, because apps with permission to write to the external
// storage can overwrite the app between F-Droid asking for it to be installed and
// the installer actually installing it.
apkToInstall.setReadable(true, false);
sanitizedApkFile.setReadable(true, false);
} catch (NumberFormatException | IOException | NoSuchAlgorithmException e) {
throw new InstallFailedException(e);
@ -151,7 +134,7 @@ public abstract class Installer {
throw new InstallFailedException("F-Droid Privileged can only be updated using an activity!");
} finally {
// 20 minutes the start of the install process, delete the file
final File apkToDelete = apkToInstall;
final File apkToDelete = sanitizedApkFile;
new Thread() {
@Override
public void run() {
@ -167,7 +150,7 @@ public abstract class Installer {
}.start();
}
return apkToInstall;
return Uri.fromFile(sanitizedApkFile);
}
public PendingIntent getPermissionScreen(Apk apk) {

View File

@ -40,6 +40,7 @@ public class InstallerFactory {
installer = new PrivilegedInstaller(context);
} else {
Log.e(TAG, "PrivilegedInstaller is enabled in prefs, but permissions are not granted!");
// TODO: better error handling?
// fallback to default installer
installer = new DefaultInstaller(context);

View File

@ -43,6 +43,8 @@ import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.installer.PrivilegedInstaller;
import java.io.File;
import eu.chainfire.libsuperuser.Shell;
/**
@ -53,7 +55,6 @@ public class InstallExtensionDialogActivity extends FragmentActivity {
private static final String TAG = "InstallIntoSystem";
public static final String ACTION_INSTALL = "install";
public static final String EXTRA_INSTALL_APK = "apk_file";
public static final String ACTION_UNINSTALL = "uninstall";
public static final String ACTION_POST_INSTALL = "post_install";
@ -73,7 +74,7 @@ public class InstallExtensionDialogActivity extends FragmentActivity {
return;
}
apkFile = getIntent().getStringExtra(EXTRA_INSTALL_APK);
apkFile = (new File(getIntent().getData().getPath())).getAbsolutePath();
switch (getIntent().getAction()) {
case ACTION_UNINSTALL: