prevent crash loop after rapid install/uninstall cycling
If you quickly cycle between installing an app and uninstalling it, then `app.installedApk` will still be null when AppDetails2.startUninstall() calls InstallerService.uninstall(). It is better to crash earlier here, before the Intent is sent with a null APK, because InstallerService is set to receive Sticky Intents. That means they will automatically be resent by the system until they successfully complete.
This commit is contained in:
parent
ea166fbc81
commit
519101a8a4
@ -32,6 +32,7 @@ import org.fdroid.fdroid.data.Apk;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This service handles the install process of apk files and
|
* This service handles the install process of apk files and
|
||||||
@ -63,6 +64,9 @@ public class InstallerService extends JobIntentService {
|
|||||||
@Override
|
@Override
|
||||||
protected void onHandleWork(@NonNull Intent intent) {
|
protected void onHandleWork(@NonNull Intent intent) {
|
||||||
final Apk apk = intent.getParcelableExtra(Installer.EXTRA_APK);
|
final Apk apk = intent.getParcelableExtra(Installer.EXTRA_APK);
|
||||||
|
if (apk == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Installer installer = InstallerFactory.create(this, apk);
|
Installer installer = InstallerFactory.create(this, apk);
|
||||||
|
|
||||||
if (ACTION_INSTALL.equals(intent.getAction())) {
|
if (ACTION_INSTALL.equals(intent.getAction())) {
|
||||||
@ -98,12 +102,17 @@ public class InstallerService extends JobIntentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install an apk from {@link Uri}
|
* Install an apk from {@link Uri}.
|
||||||
|
* <p>
|
||||||
|
* This does not include the same level of input validation as
|
||||||
|
* {@link #uninstall(Context, Apk)} since this is called in one place where
|
||||||
|
* the input has already been validated.
|
||||||
*
|
*
|
||||||
* @param context this app's {@link Context}
|
* @param context this app's {@link Context}
|
||||||
* @param localApkUri {@link Uri} pointing to (downloaded) local apk file
|
* @param localApkUri {@link Uri} pointing to (downloaded) local apk file
|
||||||
* @param downloadUri {@link Uri} where the apk has been downloaded from
|
* @param downloadUri {@link Uri} where the apk has been downloaded from
|
||||||
* @param apk apk object of app that should be installed
|
* @param apk apk object of app that should be installed
|
||||||
|
* @see #uninstall(Context, Apk)
|
||||||
*/
|
*/
|
||||||
public static void install(Context context, Uri localApkUri, Uri downloadUri, Apk apk) {
|
public static void install(Context context, Uri localApkUri, Uri downloadUri, Apk apk) {
|
||||||
Intent intent = new Intent(context, InstallerService.class);
|
Intent intent = new Intent(context, InstallerService.class);
|
||||||
@ -115,12 +124,24 @@ public class InstallerService extends JobIntentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uninstall an app
|
* Uninstall an app. {@link Objects#requireNonNull(Object)} is used to
|
||||||
|
* enforce the {@code @NonNull} requirement, since that annotation alone
|
||||||
|
* is not enough to catch all possible nulls.
|
||||||
|
* <p>
|
||||||
|
* If you quickly cycle between installing an app and uninstalling it, then
|
||||||
|
* {@link org.fdroid.fdroid.data.App#installedApk} will still be null when
|
||||||
|
* {@link org.fdroid.fdroid.AppDetails2#startUninstall()} calls
|
||||||
|
* this method. It is better to crash earlier here, before the {@link Intent}
|
||||||
|
* is sent with a null {@link Apk} instance since this service is set to
|
||||||
|
* receive Sticky Intents. That means they will automatically be resent
|
||||||
|
* by the system until they successfully complete. If an {@code Intent}
|
||||||
|
* with a null {@code Apk} is sent, it'll crash.
|
||||||
*
|
*
|
||||||
* @param context this app's {@link Context}
|
* @param context this app's {@link Context}
|
||||||
* @param apk {@link Apk} instance of the app that will be uninstalled
|
* @param apk {@link Apk} instance of the app that will be uninstalled
|
||||||
*/
|
*/
|
||||||
public static void uninstall(Context context, Apk apk) {
|
public static void uninstall(Context context, @NonNull Apk apk) {
|
||||||
|
Objects.requireNonNull(apk);
|
||||||
Intent intent = new Intent(context, InstallerService.class);
|
Intent intent = new Intent(context, InstallerService.class);
|
||||||
intent.setAction(ACTION_UNINSTALL);
|
intent.setAction(ACTION_UNINSTALL);
|
||||||
intent.putExtra(Installer.EXTRA_APK, apk);
|
intent.putExtra(Installer.EXTRA_APK, apk);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user