Don't try to notify the user for apks which are already installed.

If an app is downloaded into our cache, but an app with the same hash is
already installed, don't bother notifying people about it.

Extracted the logic for finding the path to an apk on disk (given a
PackageInfo object) to also be used by AppUpdateStatusSerice.

Change logging so that if we discard a downloaded file we Log.i instead
of Utils.debugLog. This is so that when debugging a release build we can
see what is happening, because this specific problem was easier to debug
with release builds (rather than setting up a custom fdroid repo).
This commit is contained in:
Peter Serwylo 2017-06-26 14:56:13 +10:00
parent d37e25db21
commit 2a40e082e6
2 changed files with 51 additions and 24 deletions

View File

@ -7,10 +7,12 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.InstalledAppProviderService;
import org.fdroid.fdroid.installer.ApkCache;
import org.fdroid.fdroid.installer.InstallManagerService;
@ -75,29 +77,45 @@ public class AppUpdateStatusService extends IntentService {
}
}
/**
* Verifies that {@param apkPath} is a valid apk which the user intends to install.
* If it is corrupted to the point where {@link PackageManager} can't read it, doesn't match the hash of any apk
* we know about in our database, is not pending install, or is already installed, then it will return null.
*/
@Nullable
private Apk processDownloadedApk(File apkPath) {
Utils.debugLog(TAG, "Checking " + apkPath);
PackageInfo downloadedInfo = getPackageManager().getPackageArchiveInfo(apkPath.getAbsolutePath(), PackageManager.GET_GIDS);
if (downloadedInfo == null) {
Utils.debugLog(TAG, "Skipping " + apkPath + " because PackageManager was unable to read it.");
Log.i(TAG, "Skipping " + apkPath + " because PackageManager was unable to read it.");
return null;
}
Utils.debugLog(TAG, "Found package for " + downloadedInfo.packageName + ", checking its hash to see if it downloaded correctly.");
Apk downloadedApk = findApkMatchingHash(apkPath);
if (downloadedApk == null) {
Utils.debugLog(TAG, "Either the apk wasn't downloaded fully, or the repo it came from has been disabled. Either way, not notifying the user about it.");
Log.i(TAG, "Either the apk wasn't downloaded fully, or the repo it came from has been disabled. Either way, not notifying the user about it.");
return null;
}
if (AppUpdateStatusManager.getInstance(this).isPendingInstall(downloadedApk.hash)) {
Utils.debugLog(TAG, downloadedApk.packageName + " is pending install, so we need to notify the user about installing it.");
return downloadedApk;
} else {
Utils.debugLog(TAG, downloadedApk.packageName + " is NOT pending install, probably just left over from a previous install.");
if (!AppUpdateStatusManager.getInstance(this).isPendingInstall(downloadedApk.hash)) {
Log.i(TAG, downloadedApk.packageName + " is NOT pending install, probably just left over from a previous install.");
return null;
}
try {
PackageInfo info = getPackageManager().getPackageInfo(downloadedApk.packageName, 0);
File pathToInstalled = InstalledAppProviderService.getPathToInstalledApk(info);
if (pathToInstalled != null && pathToInstalled.canRead() &&
TextUtils.equals(Utils.getBinaryHash(pathToInstalled, "sha256"), downloadedApk.hash)) {
Log.i(TAG, downloadedApk.packageName + " is pending install, but we already have the correct version installed.");
AppUpdateStatusManager.getInstance(this).markAsNoLongerPendingInstall(downloadedApk.getUrl());
return null;
}
} catch (PackageManager.NameNotFoundException ignored) { }
Utils.debugLog(TAG, downloadedApk.packageName + " is pending install, so we need to notify the user about installing it.");
return downloadedApk;
}
/**

View File

@ -188,6 +188,29 @@ public class InstalledAppProviderService extends IntentService {
}
}
@Nullable
public static File getPathToInstalledApk(PackageInfo packageInfo) {
File apk = new File(packageInfo.applicationInfo.publicSourceDir);
if (apk.isDirectory()) {
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".apk");
}
};
File[] files = apk.listFiles(filter);
if (files == null) {
String msg = packageInfo.packageName + " sourceDir has no APKs: " + apk.getAbsolutePath();
Utils.debugLog(TAG, msg);
ACRA.getErrorReporter().handleException(new IllegalArgumentException(msg), false);
return null;
}
apk = files[0];
}
return apk;
}
@Override
protected void onHandleIntent(Intent intent) {
Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
@ -201,23 +224,9 @@ public class InstalledAppProviderService extends IntentService {
PackageInfo packageInfo = getPackageInfo(intent, packageName);
if (packageInfo != null) {
Log.i(TAG, "Marking " + packageName + " as installed");
File apk = new File(packageInfo.applicationInfo.publicSourceDir);
if (apk.isDirectory()) {
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".apk");
}
};
File[] files = apk.listFiles(filter);
if (files == null) {
String msg = packageName + " sourceDir has no APKs: "
+ apk.getAbsolutePath();
Utils.debugLog(TAG, msg);
ACRA.getErrorReporter().handleException(new IllegalArgumentException(msg), false);
return;
}
apk = files[0];
File apk = getPathToInstalledApk(packageInfo);
if (apk == null) {
return;
}
if (apk.exists() && apk.canRead()) {
try {