Use Uris more often instead of File
This commit is contained in:
parent
a2356b05d6
commit
bb273cd2f5
@ -4,6 +4,7 @@ import android.app.PendingIntent;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.fdroid.fdroid.BuildConfig;
|
import org.fdroid.fdroid.BuildConfig;
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
@ -21,21 +22,17 @@ public class DefaultInstaller extends Installer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
|
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
|
||||||
|
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
|
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
|
||||||
|
|
||||||
Utils.debugLog(TAG, "ACTION_INSTALL uri: " + uri + " file: " + new File(uri.getPath()));
|
Utils.debugLog(TAG, "ACTION_INSTALL uri: " + uri + " file: " + new File(uri.getPath()));
|
||||||
|
|
||||||
// TODO: rework for uri
|
Uri sanitizedUri;
|
||||||
File sanitizedFile = null;
|
|
||||||
try {
|
try {
|
||||||
sanitizedFile = Installer.prepareApkFile(mContext, new File(uri.getPath()), packageName);
|
sanitizedUri = Installer.prepareApkFile(mContext, uri, packageName);
|
||||||
} catch (Installer.InstallFailedException e) {
|
} 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;
|
Intent installIntent;
|
||||||
// special case: F-Droid Privileged Extension
|
// 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
|
// 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
|
// NOTE: Disabled for debug builds to be able to use official extension from repo
|
||||||
ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(mContext);
|
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!");
|
throw new RuntimeException("APK signature of extension not correct!");
|
||||||
}
|
}
|
||||||
|
|
||||||
installIntent = new Intent(mContext, InstallExtensionDialogActivity.class);
|
installIntent = new Intent(mContext, InstallExtensionDialogActivity.class);
|
||||||
installIntent.setAction(InstallExtensionDialogActivity.ACTION_INSTALL);
|
installIntent.setAction(InstallExtensionDialogActivity.ACTION_INSTALL);
|
||||||
installIntent.putExtra(InstallExtensionDialogActivity.EXTRA_INSTALL_APK,
|
installIntent.setData(sanitizedUri);
|
||||||
sanitizedFile.getAbsolutePath());
|
|
||||||
} else {
|
} else {
|
||||||
installIntent = new Intent(mContext, AndroidInstallerActivity.class);
|
installIntent = new Intent(mContext, AndroidInstallerActivity.class);
|
||||||
installIntent.setAction(AndroidInstallerActivity.ACTION_INSTALL_PACKAGE);
|
installIntent.setAction(AndroidInstallerActivity.ACTION_INSTALL_PACKAGE);
|
||||||
|
@ -37,7 +37,6 @@ import org.fdroid.fdroid.data.ApkProvider;
|
|||||||
import org.fdroid.fdroid.data.SanitizedFile;
|
import org.fdroid.fdroid.data.SanitizedFile;
|
||||||
import org.fdroid.fdroid.privileged.views.AppDiff;
|
import org.fdroid.fdroid.privileged.views.AppDiff;
|
||||||
import org.fdroid.fdroid.privileged.views.AppSecurityPermissions;
|
import org.fdroid.fdroid.privileged.views.AppSecurityPermissions;
|
||||||
import org.fdroid.fdroid.privileged.views.InstallConfirmActivity;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
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) {
|
Installer(Context context) {
|
||||||
this.mContext = context;
|
this.mContext = context;
|
||||||
this.mPm = context.getPackageManager();
|
this.mPm = context.getPackageManager();
|
||||||
localBroadcastManager = LocalBroadcastManager.getInstance(context);
|
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 {
|
throws InstallFailedException {
|
||||||
SanitizedFile apkToInstall = null;
|
|
||||||
|
File apkFile = new File(uri.getPath());
|
||||||
|
|
||||||
|
SanitizedFile sanitizedApkFile = null;
|
||||||
try {
|
try {
|
||||||
Map<String, Object> attributes = AndroidXMLDecompress.getManifestHeaderAttributes(apkFile.getAbsolutePath());
|
Map<String, Object> attributes = AndroidXMLDecompress.getManifestHeaderAttributes(apkFile.getAbsolutePath());
|
||||||
|
|
||||||
/* This isn't really needed, but might as well since we have the data already */
|
/* 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"))) {
|
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")) {
|
if (!attributes.containsKey("versionCode")) {
|
||||||
throw new InstallFailedException(apkFile + " is missing versionCode!");
|
throw new InstallFailedException(uri + " is missing versionCode!");
|
||||||
}
|
}
|
||||||
int versionCode = (Integer) attributes.get("versionCode");
|
int versionCode = (Integer) attributes.get("versionCode");
|
||||||
Apk apk = ApkProvider.Helper.find(context, packageName, versionCode, new String[]{
|
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
|
* of the app to prevent attacks based on other apps swapping the file
|
||||||
* out during the install process. Most likely, apkFile was just downloaded,
|
* out during the install process. Most likely, apkFile was just downloaded,
|
||||||
* so it should still be in the RAM disk cache */
|
* 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()));
|
context.getFilesDir()));
|
||||||
FileUtils.copyFile(apkFile, apkToInstall);
|
FileUtils.copyFile(apkFile, sanitizedApkFile);
|
||||||
if (!verifyApkFile(apkToInstall, apk.hash, apk.hashType)) {
|
if (!verifyApkFile(sanitizedApkFile, apk.hash, apk.hashType)) {
|
||||||
FileUtils.deleteQuietly(apkFile);
|
FileUtils.deleteQuietly(apkFile);
|
||||||
throw new InstallFailedException(apkFile + " failed to verify!");
|
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
|
// 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
|
// storage can overwrite the app between F-Droid asking for it to be installed and
|
||||||
// the installer actually installing it.
|
// the installer actually installing it.
|
||||||
apkToInstall.setReadable(true, false);
|
sanitizedApkFile.setReadable(true, false);
|
||||||
|
|
||||||
} catch (NumberFormatException | IOException | NoSuchAlgorithmException e) {
|
} catch (NumberFormatException | IOException | NoSuchAlgorithmException e) {
|
||||||
throw new InstallFailedException(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!");
|
throw new InstallFailedException("F-Droid Privileged can only be updated using an activity!");
|
||||||
} finally {
|
} finally {
|
||||||
// 20 minutes the start of the install process, delete the file
|
// 20 minutes the start of the install process, delete the file
|
||||||
final File apkToDelete = apkToInstall;
|
final File apkToDelete = sanitizedApkFile;
|
||||||
new Thread() {
|
new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -167,7 +150,7 @@ public abstract class Installer {
|
|||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
return apkToInstall;
|
return Uri.fromFile(sanitizedApkFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PendingIntent getPermissionScreen(Apk apk) {
|
public PendingIntent getPermissionScreen(Apk apk) {
|
||||||
|
@ -40,6 +40,7 @@ public class InstallerFactory {
|
|||||||
installer = new PrivilegedInstaller(context);
|
installer = new PrivilegedInstaller(context);
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "PrivilegedInstaller is enabled in prefs, but permissions are not granted!");
|
Log.e(TAG, "PrivilegedInstaller is enabled in prefs, but permissions are not granted!");
|
||||||
|
// TODO: better error handling?
|
||||||
|
|
||||||
// fallback to default installer
|
// fallback to default installer
|
||||||
installer = new DefaultInstaller(context);
|
installer = new DefaultInstaller(context);
|
||||||
|
@ -43,6 +43,8 @@ import org.fdroid.fdroid.Preferences;
|
|||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.installer.PrivilegedInstaller;
|
import org.fdroid.fdroid.installer.PrivilegedInstaller;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import eu.chainfire.libsuperuser.Shell;
|
import eu.chainfire.libsuperuser.Shell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +55,6 @@ public class InstallExtensionDialogActivity extends FragmentActivity {
|
|||||||
private static final String TAG = "InstallIntoSystem";
|
private static final String TAG = "InstallIntoSystem";
|
||||||
|
|
||||||
public static final String ACTION_INSTALL = "install";
|
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_UNINSTALL = "uninstall";
|
||||||
public static final String ACTION_POST_INSTALL = "post_install";
|
public static final String ACTION_POST_INSTALL = "post_install";
|
||||||
@ -73,7 +74,7 @@ public class InstallExtensionDialogActivity extends FragmentActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
apkFile = getIntent().getStringExtra(EXTRA_INSTALL_APK);
|
apkFile = (new File(getIntent().getData().getPath())).getAbsolutePath();
|
||||||
|
|
||||||
switch (getIntent().getAction()) {
|
switch (getIntent().getAction()) {
|
||||||
case ACTION_UNINSTALL:
|
case ACTION_UNINSTALL:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user