From 71db322b6d7a800d563b77578ce4cdc3a5eb2361 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Thu, 24 Apr 2014 07:58:19 +0930 Subject: [PATCH] Don't implement 'update' for installed apps, use replace (Fixes #14) There were some weird edge cases that couldn't quite be pinned down, whereby installing an app would result in a unique key violation being hit. One example was when somebody was installing an apk from a file manager. It seems that this doesn't trigger a PACKAGE_CHANGED, but rather a PACKAGE_INSTALLED. The end result is that it attempts to insert a record that already exists in the installed apps table. Because we have a unique key constraing on the appId, it breaks. This commit changes the way that we insert installed app details. Instead of inserting some times, and updating other times, we always insert. If we hit a unique key violation, the row is deleted, and then the new values are reinserted. --- .../fdroid/PackageUpgradedReceiver.java | 5 ++-- .../fdroid/data/InstalledAppCacheUpdater.java | 28 ++----------------- .../fdroid/data/InstalledAppProvider.java | 17 ++--------- .../fdroid/InstalledAppProviderTest.java | 18 +++++++++--- 4 files changed, 22 insertions(+), 46 deletions(-) diff --git a/src/org/fdroid/fdroid/PackageUpgradedReceiver.java b/src/org/fdroid/fdroid/PackageUpgradedReceiver.java index 516a9660d..404818881 100644 --- a/src/org/fdroid/fdroid/PackageUpgradedReceiver.java +++ b/src/org/fdroid/fdroid/PackageUpgradedReceiver.java @@ -39,11 +39,12 @@ public class PackageUpgradedReceiver extends PackageReceiver { Log.d("FDroid", "Updating installed app info for '" + appId + "' to v" + info.versionCode + " (" + info.versionName + ")"); - Uri uri = InstalledAppProvider.getAppUri(appId); + Uri uri = InstalledAppProvider.getContentUri(); ContentValues values = new ContentValues(1); + values.put(InstalledAppProvider.DataColumns.APP_ID, info.packageName); values.put(InstalledAppProvider.DataColumns.VERSION_CODE, info.versionCode); values.put(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName); - context.getContentResolver().update(uri, values, null, null); + context.getContentResolver().insert(uri, values); } } \ No newline at end of file diff --git a/src/org/fdroid/fdroid/data/InstalledAppCacheUpdater.java b/src/org/fdroid/fdroid/data/InstalledAppCacheUpdater.java index 7d7b65d22..edb4ae5b3 100644 --- a/src/org/fdroid/fdroid/data/InstalledAppCacheUpdater.java +++ b/src/org/fdroid/fdroid/data/InstalledAppCacheUpdater.java @@ -27,7 +27,6 @@ public class InstalledAppCacheUpdater { private Context context; private List toInsert = new ArrayList(); - private List toUpdate = new ArrayList(); private List toDelete = new ArrayList(); protected InstalledAppCacheUpdater(Context context) { @@ -85,14 +84,13 @@ public class InstalledAppCacheUpdater { * then the cache has changed. */ private boolean hasChanged() { - return toInsert.size() > 0 || toUpdate.size() > 0 || toDelete.size() > 0; + return toInsert.size() > 0 || toDelete.size() > 0; } private void updateCache() { ArrayList ops = new ArrayList(); ops.addAll(deleteFromCache(toDelete)); - ops.addAll(updateCachedValues(toUpdate)); ops.addAll(insertIntoCache(toInsert)); if (ops.size() > 0) { @@ -114,12 +112,8 @@ public class InstalledAppCacheUpdater { List installedPackages = context.getPackageManager().getInstalledPackages(0); for (PackageInfo appInfo : installedPackages) { - if (!cachedInfo.containsKey(appInfo.packageName)) { - toInsert.add(appInfo); - } else { - if (cachedInfo.get(appInfo.packageName) < appInfo.versionCode) { - toUpdate.add(appInfo); - } + toInsert.add(appInfo); + if (cachedInfo.containsKey(appInfo.packageName)) { cachedInfo.remove(appInfo.packageName); } } @@ -148,22 +142,6 @@ public class InstalledAppCacheUpdater { return ops; } - private List updateCachedValues(List appsToUpdate) { - List ops = new ArrayList(appsToUpdate.size()); - if (appsToUpdate.size() > 0) { - Log.d(TAG, "Preparing to update installed app cache for " + appsToUpdate.size() + " apps."); - for (PackageInfo info : appsToUpdate) { - Uri uri = InstalledAppProvider.getAppUri(info.packageName); - ContentProviderOperation op = ContentProviderOperation.newUpdate(uri) - .withValue(InstalledAppProvider.DataColumns.VERSION_CODE, info.versionCode) - .withValue(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName) - .build(); - ops.add(op); - } - } - return ops; - } - private List deleteFromCache(List appIds) { List ops = new ArrayList(appIds.size()); if (appIds.size() > 0) { diff --git a/src/org/fdroid/fdroid/data/InstalledAppProvider.java b/src/org/fdroid/fdroid/data/InstalledAppProvider.java index 20cacc656..249e4bf01 100644 --- a/src/org/fdroid/fdroid/data/InstalledAppProvider.java +++ b/src/org/fdroid/fdroid/data/InstalledAppProvider.java @@ -140,7 +140,7 @@ public class InstalledAppProvider extends FDroidProvider { } verifyVersionNameNotNull(values); - write().insertOrThrow(getTableName(), null, values); + write().replaceOrThrow(getTableName(), null, values); if (!isApplyingBatch()) { getContext().getContentResolver().notifyChange(uri, null); } @@ -149,20 +149,7 @@ public class InstalledAppProvider extends FDroidProvider { @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { - - if (matcher.match(uri) != CODE_SINGLE) { - throw new UnsupportedOperationException("Update not supported for " + uri + "."); - } - - QuerySelection query = new QuerySelection(where, whereArgs); - query = query.add(queryApp(uri.getLastPathSegment())); - - verifyVersionNameNotNull(values); - int count = write().update(getTableName(), values, query.getSelection(), query.getArgs()); - if (!isApplyingBatch()) { - getContext().getContentResolver().notifyChange(uri, null); - } - return count; + throw new UnsupportedOperationException("\"Update' not supported for installed appp provider. Instead, you should insert, and it will overwrite the relevant rows if one exists."); } /** diff --git a/test/src/org/fdroid/fdroid/InstalledAppProviderTest.java b/test/src/org/fdroid/fdroid/InstalledAppProviderTest.java index 017ac4e7a..14ff885c9 100644 --- a/test/src/org/fdroid/fdroid/InstalledAppProviderTest.java +++ b/test/src/org/fdroid/fdroid/InstalledAppProviderTest.java @@ -60,10 +60,20 @@ public class InstalledAppProviderTest extends FDroidProviderTest