Save app details to temp table, then flush after update verified.
This commit is contained in:
parent
9a2d390279
commit
cc0adcc5ad
@ -88,6 +88,11 @@
|
||||
android:name="org.fdroid.fdroid.data.TempApkProvider"
|
||||
android:exported="false"/>
|
||||
|
||||
<provider
|
||||
android:authorities="org.fdroid.fdroid.data.TempAppProvider"
|
||||
android:name="org.fdroid.fdroid.data.TempAppProvider"
|
||||
android:exported="false"/>
|
||||
|
||||
<provider
|
||||
android:authorities="org.fdroid.fdroid.data.InstalledAppProvider"
|
||||
android:name="org.fdroid.fdroid.data.InstalledAppProvider"
|
||||
|
@ -18,6 +18,7 @@ import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.data.TempApkProvider;
|
||||
import org.fdroid.fdroid.data.TempAppProvider;
|
||||
import org.fdroid.fdroid.net.Downloader;
|
||||
import org.fdroid.fdroid.net.DownloaderFactory;
|
||||
import org.xml.sax.InputSource;
|
||||
@ -203,12 +204,14 @@ public class RepoUpdater {
|
||||
}
|
||||
|
||||
private void flushBufferToDb() throws UpdateException {
|
||||
Log.d(TAG, "Flushing details of " + MAX_APP_BUFFER + " and their packages to the database.");
|
||||
if (apksToSave.size() > 0 || appsToSave.size() > 0) {
|
||||
Log.d(TAG, "Flushing details of up to " + MAX_APP_BUFFER + " apps and their packages to the database.");
|
||||
flushAppsToDbInBatch();
|
||||
flushApksToDbInBatch();
|
||||
apksToSave.clear();
|
||||
appsToSave.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void flushApksToDbInBatch() throws UpdateException {
|
||||
List<Apk> apksToSaveList = new ArrayList<>();
|
||||
@ -236,7 +239,7 @@ public class RepoUpdater {
|
||||
ArrayList<ContentProviderOperation> appOperations = insertOrUpdateApps(appsToSave);
|
||||
|
||||
try {
|
||||
context.getContentResolver().applyBatch(AppProvider.getAuthority(), appOperations);
|
||||
context.getContentResolver().applyBatch(TempAppProvider.getAuthority(), appOperations);
|
||||
} catch (RemoteException|OperationApplicationException e) {
|
||||
Log.e(TAG, "Error updating apps", e);
|
||||
throw new UpdateException(repo, "Error updating apps: " + e.getMessage(), e);
|
||||
@ -290,7 +293,7 @@ public class RepoUpdater {
|
||||
* <strong>Does not do any checks to see if the app already exists or not.</strong>
|
||||
*/
|
||||
private ContentProviderOperation updateExistingApp(App app) {
|
||||
Uri uri = AppProvider.getContentUri(app);
|
||||
Uri uri = TempAppProvider.getAppUri(app);
|
||||
ContentValues values = app.toContentValues();
|
||||
for (final String toIgnore : APP_FIELDS_TO_IGNORE) {
|
||||
if (values.containsKey(toIgnore)) {
|
||||
@ -306,7 +309,7 @@ public class RepoUpdater {
|
||||
*/
|
||||
private ContentProviderOperation insertNewApp(App app) {
|
||||
ContentValues values = app.toContentValues();
|
||||
Uri uri = AppProvider.getContentUri();
|
||||
Uri uri = TempAppProvider.getContentUri();
|
||||
return ContentProviderOperation.newInsert(uri).withValues(values).build();
|
||||
}
|
||||
|
||||
@ -415,6 +418,7 @@ public class RepoUpdater {
|
||||
// the index was signed with until we've finished reading it - and we don't
|
||||
// want to put stuff in the real database until we are sure it is from a
|
||||
// trusted source.
|
||||
TempAppProvider.Helper.init(context);
|
||||
TempApkProvider.Helper.init(context);
|
||||
|
||||
// Due to a bug in Android 5.0 Lollipop, the inclusion of spongycastle causes
|
||||
@ -433,12 +437,17 @@ public class RepoUpdater {
|
||||
final RepoXMLHandler repoXMLHandler = new RepoXMLHandler(repo, createIndexReceiver());
|
||||
reader.setContentHandler(repoXMLHandler);
|
||||
reader.parse(new InputSource(indexInputStream));
|
||||
|
||||
flushBufferToDb();
|
||||
|
||||
signingCertFromJar = getSigningCertFromJar(indexEntry);
|
||||
|
||||
// JarEntry can only read certificates after the file represented by that JarEntry
|
||||
// has been read completely, so verification cannot run until now...
|
||||
assertSigningCertFromXmlCorrect();
|
||||
|
||||
Log.i(TAG, "Repo signature verified, saving app metadata to database.");
|
||||
TempAppProvider.Helper.commit(context);
|
||||
TempApkProvider.Helper.commit(context);
|
||||
RepoProvider.Helper.update(context, repo, repoDetailsToSave);
|
||||
|
||||
|
@ -31,14 +31,12 @@ public class TempApkProvider extends ApkProvider {
|
||||
|
||||
private static final int CODE_INIT = 10000;
|
||||
private static final int CODE_COMMIT = CODE_INIT + 1;
|
||||
private static final int CODE_ROLLBACK = CODE_INIT + 2;
|
||||
|
||||
private static final UriMatcher matcher = new UriMatcher(-1);
|
||||
|
||||
static {
|
||||
matcher.addURI(getAuthority(), PATH_INIT, CODE_INIT);
|
||||
matcher.addURI(getAuthority(), PATH_COMMIT, CODE_COMMIT);
|
||||
matcher.addURI(getAuthority(), PATH_ROLLBACK, CODE_ROLLBACK);
|
||||
matcher.addURI(getAuthority(), PATH_APK + "/#/*", CODE_SINGLE);
|
||||
matcher.addURI(getAuthority(), PATH_REPO_APK + "/#/*", CODE_REPO_APK);
|
||||
}
|
||||
@ -94,14 +92,6 @@ public class TempApkProvider extends ApkProvider {
|
||||
context.getContentResolver().insert(uri, new ContentValues());
|
||||
}
|
||||
|
||||
/**
|
||||
* Not sure that this is strictly necessary, but this will remove the temp table.
|
||||
*/
|
||||
public static void rollback(Context context) {
|
||||
Uri uri = Uri.withAppendedPath(getContentUri(), PATH_ROLLBACK);
|
||||
context.getContentResolver().insert(uri, new ContentValues());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -114,16 +104,13 @@ public class TempApkProvider extends ApkProvider {
|
||||
} else if (code == CODE_COMMIT) {
|
||||
commitTable();
|
||||
return null;
|
||||
} else if (code == CODE_ROLLBACK) {
|
||||
removeTable();
|
||||
return null;
|
||||
} else {
|
||||
return super.insert(uri, values);
|
||||
}
|
||||
}
|
||||
|
||||
private void initTable() {
|
||||
removeTable();
|
||||
write().execSQL("DROP TABLE IF EXISTS " + getTableName());
|
||||
write().execSQL("CREATE TEMPORARY TABLE " + getTableName() + " AS SELECT * FROM " + DBHelper.TABLE_APK);
|
||||
}
|
||||
|
||||
|
103
F-Droid/src/org/fdroid/fdroid/data/TempAppProvider.java
Normal file
103
F-Droid/src/org/fdroid/fdroid/data/TempAppProvider.java
Normal file
@ -0,0 +1,103 @@
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.UriMatcher;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class does all of its operations in a temporary sqlite table.
|
||||
*/
|
||||
public class TempAppProvider extends AppProvider {
|
||||
|
||||
private static final String TAG = "TempAppProvider";
|
||||
|
||||
private static final String PROVIDER_NAME = "TempAppProvider";
|
||||
|
||||
private static final String PATH_INIT = "init";
|
||||
private static final String PATH_COMMIT = "commit";
|
||||
private static final String PATH_ROLLBACK = "rollback";
|
||||
|
||||
private static final int CODE_INIT = 10000;
|
||||
private static final int CODE_COMMIT = CODE_INIT + 1;
|
||||
|
||||
private static final UriMatcher matcher = new UriMatcher(-1);
|
||||
|
||||
static {
|
||||
matcher.addURI(getAuthority(), PATH_INIT, CODE_INIT);
|
||||
matcher.addURI(getAuthority(), PATH_COMMIT, CODE_COMMIT);
|
||||
matcher.addURI(getAuthority(), "*", CODE_SINGLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTableName() {
|
||||
return "temp_" + super.getTableName();
|
||||
}
|
||||
|
||||
public static String getAuthority() {
|
||||
return AUTHORITY + "." + PROVIDER_NAME;
|
||||
}
|
||||
|
||||
public static Uri getContentUri() {
|
||||
return Uri.parse("content://" + getAuthority());
|
||||
}
|
||||
|
||||
public static Uri getAppUri(App app) {
|
||||
return Uri.withAppendedPath(getContentUri(), app.id);
|
||||
}
|
||||
|
||||
public static class Helper {
|
||||
|
||||
/**
|
||||
* Deletes the old temporary table (if it exists). Then creates a new temporary apk provider
|
||||
* table and populates it with all the data from the real apk provider table.
|
||||
*/
|
||||
public static void init(Context context) {
|
||||
Uri uri = Uri.withAppendedPath(getContentUri(), PATH_INIT);
|
||||
context.getContentResolver().insert(uri, new ContentValues());
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves data from the temp table to the apk table, by removing _EVERYTHING_ from the real
|
||||
* apk table and inserting all of the records from here. The temporary table is then removed.
|
||||
*/
|
||||
public static void commit(Context context) {
|
||||
Uri uri = Uri.withAppendedPath(getContentUri(), PATH_COMMIT);
|
||||
context.getContentResolver().insert(uri, new ContentValues());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
int code = matcher.match(uri);
|
||||
|
||||
if (code == CODE_INIT) {
|
||||
initTable();
|
||||
return null;
|
||||
} else if (code == CODE_COMMIT) {
|
||||
commitTable();
|
||||
return null;
|
||||
} else {
|
||||
return super.insert(uri, values);
|
||||
}
|
||||
}
|
||||
|
||||
private void initTable() {
|
||||
write().execSQL("DROP TABLE IF EXISTS " + getTableName());
|
||||
write().execSQL("CREATE TEMPORARY TABLE " + getTableName() + " AS SELECT * FROM " + DBHelper.TABLE_APP);
|
||||
}
|
||||
|
||||
private void commitTable() {
|
||||
Log.d(TAG, "Deleting all apks from " + DBHelper.TABLE_APP + " so they can be copied from " + getTableName());
|
||||
write().execSQL("DELETE FROM " + DBHelper.TABLE_APP);
|
||||
write().execSQL("INSERT INTO " + DBHelper.TABLE_APP + " SELECT * FROM " + getTableName());
|
||||
}
|
||||
|
||||
private void removeTable() {
|
||||
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user