From eefbee969e7641f369ab8c10a4db451e70730a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Thu, 22 Oct 2015 19:42:39 +0200 Subject: [PATCH] Store installed app signature in cache This means we can fetch the signatures only once instead of every time we need them. Start by using the cache in AppDetails. --- F-Droid/src/org/fdroid/fdroid/AppDetails.java | 46 +++---------------- F-Droid/src/org/fdroid/fdroid/data/App.java | 5 ++ .../org/fdroid/fdroid/data/AppProvider.java | 12 +++++ .../src/org/fdroid/fdroid/data/DBHelper.java | 20 ++++---- .../fdroid/data/InstalledAppCacheUpdater.java | 6 ++- .../fdroid/data/InstalledAppProvider.java | 18 ++++++++ .../fdroid/receiver/PackageAddedReceiver.java | 2 + .../fdroid/receiver/PackageReceiver.java | 2 +- .../receiver/PackageUpgradedReceiver.java | 2 + 9 files changed, 62 insertions(+), 51 deletions(-) diff --git a/F-Droid/src/org/fdroid/fdroid/AppDetails.java b/F-Droid/src/org/fdroid/fdroid/AppDetails.java index a975ab49d..8bdd389f9 100644 --- a/F-Droid/src/org/fdroid/fdroid/AppDetails.java +++ b/F-Droid/src/org/fdroid/fdroid/AppDetails.java @@ -30,7 +30,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.database.ContentObserver; import android.graphics.Bitmap; @@ -96,7 +95,6 @@ import org.fdroid.fdroid.net.AsyncDownloaderFromAndroid; import org.fdroid.fdroid.net.Downloader; import java.io.File; -import java.security.NoSuchAlgorithmException; import java.util.Iterator; import java.util.List; @@ -104,8 +102,6 @@ interface AppDetailsData { App getApp(); AppDetails.ApkListAdapter getApks(); - - String getInstalledSigHash(); } /** @@ -188,8 +184,8 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A return getString(R.string.app_not_installed); } // Definitely installed this version. - if (mInstalledSigID != null && apk.sig != null - && apk.sig.equals(mInstalledSigID)) { + if (app.installedSig != null && apk.sig != null + && apk.sig.equals(app.installedSig)) { return getString(R.string.app_installed); } // Installed the same version, but from someplace else. @@ -447,9 +443,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A } - // The signature of the installed version. - private String mInstalledSigID; - @Override protected void onStart() { super.onStart(); @@ -601,7 +594,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A * like that) and then finish the activity. */ private void setApp(App newApp) { - if (newApp == null) { Toast.makeText(this, R.string.no_such_app, Toast.LENGTH_LONG).show(); finish(); @@ -612,21 +604,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A startingIgnoreAll = app.ignoreAllUpdates; startingIgnoreThis = app.ignoreThisUpdate; - - // Get the signature of the installed package... - mInstalledSigID = null; - - if (app.isInstalled()) { - try { - PackageInfo pi = mPm.getPackageInfo(app.id, PackageManager.GET_SIGNATURES); - Hasher hash = new Hasher("MD5", pi.signatures[0].toCharsString().getBytes()); - mInstalledSigID = hash.getHash(); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Failed to get installed signature"); - } catch (NoSuchAlgorithmException e) { - Log.w(TAG, "Failed to calculate signature MD5 sum"); - } - } } private void refreshApkList() { @@ -853,8 +830,8 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A alert.show(); return; } - if (mInstalledSigID != null && apk.sig != null - && !apk.sig.equals(mInstalledSigID)) { + if (app.installedSig != null && apk.sig != null + && !apk.sig.equals(app.installedSig)) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(R.string.SignatureMismatch).setPositiveButton( R.string.ok, @@ -1044,11 +1021,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A return adapter; } - @Override - public String getInstalledSigHash() { - return mInstalledSigID; - } - public static class AppDetailsSummaryFragment extends Fragment { protected final Preferences prefs; @@ -1092,10 +1064,6 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A return data.getApks(); } - protected String getInstalledSigHash() { - return data.getInstalledSigHash(); - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); @@ -1408,11 +1376,11 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A return; } + App app = getApp(); TextView signatureView = (TextView) view.findViewById(R.id.signature); - String sig = getInstalledSigHash(); - if (prefs.expertMode() && !TextUtils.isEmpty(sig)) { + if (prefs.expertMode() && !TextUtils.isEmpty(app.installedSig)) { signatureView.setVisibility(View.VISIBLE); - signatureView.setText("Signed: " + sig); + signatureView.setText("Signed: " + app.installedSig); } else { signatureView.setVisibility(View.GONE); } diff --git a/F-Droid/src/org/fdroid/fdroid/data/App.java b/F-Droid/src/org/fdroid/fdroid/data/App.java index 5416617a7..02f131a9e 100644 --- a/F-Droid/src/org/fdroid/fdroid/data/App.java +++ b/F-Droid/src/org/fdroid/fdroid/data/App.java @@ -100,6 +100,8 @@ public class App extends ValueObject implements Comparable { public Apk installedApk; // might be null if not installed + public String installedSig; + public boolean system; public boolean updatedSystemApp; @@ -209,6 +211,9 @@ public class App extends ValueObject implements Comparable { case AppProvider.DataColumns.InstalledApp.VERSION_NAME: installedVersionName = cursor.getString(i); break; + case AppProvider.DataColumns.InstalledApp.SIGNATURE: + installedSig = cursor.getString(i); + break; case "_id": break; default: diff --git a/F-Droid/src/org/fdroid/fdroid/data/AppProvider.java b/F-Droid/src/org/fdroid/fdroid/data/AppProvider.java index 8f992408f..1033e799f 100644 --- a/F-Droid/src/org/fdroid/fdroid/data/AppProvider.java +++ b/F-Droid/src/org/fdroid/fdroid/data/AppProvider.java @@ -209,6 +209,7 @@ public class AppProvider extends FDroidProvider { interface InstalledApp { String VERSION_CODE = "installedVersionCode"; String VERSION_NAME = "installedVersionName"; + String SIGNATURE = "installedSig"; } String[] ALL = { @@ -220,6 +221,7 @@ public class AppProvider extends FDroidProvider { IGNORE_THISUPDATE, ICON_URL, ICON_URL_LARGE, SUGGESTED_VERSION_CODE, SuggestedApk.VERSION, InstalledApp.VERSION_CODE, InstalledApp.VERSION_NAME, + InstalledApp.SIGNATURE, }; } @@ -354,6 +356,9 @@ public class AppProvider extends FDroidProvider { case DataColumns.InstalledApp.VERSION_CODE: addInstalledAppVersionCode(); break; + case DataColumns.InstalledApp.SIGNATURE: + addInstalledSig(); + break; case DataColumns._COUNT: appendCountField(); break; @@ -402,6 +407,13 @@ public class AppProvider extends FDroidProvider { ); } + private void addInstalledSig() { + addInstalledAppField( + InstalledAppProvider.DataColumns.SIGNATURE, + DataColumns.InstalledApp.SIGNATURE + ); + } + private void addInstalledAppField(String fieldName, String alias) { leftJoinToInstalledTable(); appendField(fieldName, "installed", alias); diff --git a/F-Droid/src/org/fdroid/fdroid/data/DBHelper.java b/F-Droid/src/org/fdroid/fdroid/data/DBHelper.java index 06895ff41..64ab6aec0 100644 --- a/F-Droid/src/org/fdroid/fdroid/data/DBHelper.java +++ b/F-Droid/src/org/fdroid/fdroid/data/DBHelper.java @@ -97,10 +97,12 @@ public class DBHelper extends SQLiteOpenHelper { + InstalledAppProvider.DataColumns.APP_ID + " TEXT NOT NULL PRIMARY KEY, " + InstalledAppProvider.DataColumns.VERSION_CODE + " INT NOT NULL, " + InstalledAppProvider.DataColumns.VERSION_NAME + " TEXT NOT NULL, " - + InstalledAppProvider.DataColumns.APPLICATION_LABEL + " TEXT NOT NULL " + + InstalledAppProvider.DataColumns.APPLICATION_LABEL + " TEXT NOT NULL, " + + InstalledAppProvider.DataColumns.SIGNATURE + " TEXT NOT NULL " + " );"; + private static final String DROP_TABLE_INSTALLED_APP = "DROP TABLE " + TABLE_INSTALLED_APP + ";"; - private static final int DB_VERSION = 50; + private static final int DB_VERSION = 51; private final Context context; @@ -278,11 +280,11 @@ public class DBHelper extends SQLiteOpenHelper { renameRepoId(db, oldVersion); populateRepoNames(db, oldVersion); if (oldVersion < 43) createInstalledApp(db); - addAppLabelToInstalledCache(db, oldVersion); addIsSwapToRepo(db, oldVersion); addChangelogToApp(db, oldVersion); addIconUrlLargeToApp(db, oldVersion); updateIconUrlLarge(db, oldVersion); + recreateInstalledCache(db, oldVersion); } /** @@ -478,13 +480,11 @@ public class DBHelper extends SQLiteOpenHelper { db.execSQL(CREATE_TABLE_INSTALLED_APP); } - private void addAppLabelToInstalledCache(SQLiteDatabase db, int oldVersion) { - if (oldVersion < 45) { - Utils.debugLog(TAG, "Adding applicationLabel to installed app table. " + - "Turns out we will need to repopulate the cache after doing this, " + - "so just dropping and recreating the table (instead of altering and adding a column). " + - "This will force the entire cache to be rebuilt, including app names."); - db.execSQL("DROP TABLE fdroid_installedApp;"); + // If any column was added or removed, just drop the table, create it + // again and let the cache be filled from scratch again. + private void recreateInstalledCache(SQLiteDatabase db, int oldVersion) { + if (oldVersion < 51) { + db.execSQL(DROP_TABLE_INSTALLED_APP); createInstalledApp(db); } } diff --git a/F-Droid/src/org/fdroid/fdroid/data/InstalledAppCacheUpdater.java b/F-Droid/src/org/fdroid/fdroid/data/InstalledAppCacheUpdater.java index ae3dd01c1..c6f802efa 100644 --- a/F-Droid/src/org/fdroid/fdroid/data/InstalledAppCacheUpdater.java +++ b/F-Droid/src/org/fdroid/fdroid/data/InstalledAppCacheUpdater.java @@ -4,6 +4,7 @@ import android.content.ContentProviderOperation; import android.content.Context; import android.content.OperationApplicationException; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.AsyncTask; import android.os.RemoteException; @@ -110,7 +111,8 @@ public class InstalledAppCacheUpdater { Map cachedInfo = InstalledAppProvider.Helper.all(context); - List installedPackages = context.getPackageManager().getInstalledPackages(0); + List installedPackages = context.getPackageManager() + .getInstalledPackages(PackageManager.GET_SIGNATURES); for (PackageInfo appInfo : installedPackages) { toInsert.add(appInfo); if (cachedInfo.containsKey(appInfo.packageName)) { @@ -137,6 +139,8 @@ public class InstalledAppCacheUpdater { .withValue(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName) .withValue(InstalledAppProvider.DataColumns.APPLICATION_LABEL, InstalledAppProvider.getApplicationLabel(context, info.packageName)) + .withValue(InstalledAppProvider.DataColumns.SIGNATURE, + InstalledAppProvider.getPackageSig(info)) .build(); ops.add(op); } diff --git a/F-Droid/src/org/fdroid/fdroid/data/InstalledAppProvider.java b/F-Droid/src/org/fdroid/fdroid/data/InstalledAppProvider.java index b2552fe23..3ce9b405e 100644 --- a/F-Droid/src/org/fdroid/fdroid/data/InstalledAppProvider.java +++ b/F-Droid/src/org/fdroid/fdroid/data/InstalledAppProvider.java @@ -4,15 +4,19 @@ import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.Signature; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.util.Log; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.Hasher; import org.fdroid.fdroid.Utils; +import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; @@ -59,9 +63,11 @@ public class InstalledAppProvider extends FDroidProvider { String VERSION_CODE = "versionCode"; String VERSION_NAME = "versionName"; String APPLICATION_LABEL = "applicationLabel"; + String SIGNATURE = "sig"; String[] ALL = { _ID, APP_ID, VERSION_CODE, VERSION_NAME, APPLICATION_LABEL, + SIGNATURE, }; } @@ -106,6 +112,18 @@ public class InstalledAppProvider extends FDroidProvider { return packageName; // all else fails, return id } + public static String getPackageSig(PackageInfo info) { + Signature sig = info.signatures[0]; + String sigHash = ""; + try { + Hasher hash = new Hasher("MD5", sig.toCharsString().getBytes()); + sigHash = hash.getHash(); + } catch (NoSuchAlgorithmException e) { + // ignore + } + return sigHash; + } + @Override protected String getTableName() { return DBHelper.TABLE_INSTALLED_APP; diff --git a/F-Droid/src/org/fdroid/fdroid/receiver/PackageAddedReceiver.java b/F-Droid/src/org/fdroid/fdroid/receiver/PackageAddedReceiver.java index 1404af51a..5a3b15787 100644 --- a/F-Droid/src/org/fdroid/fdroid/receiver/PackageAddedReceiver.java +++ b/F-Droid/src/org/fdroid/fdroid/receiver/PackageAddedReceiver.java @@ -57,6 +57,8 @@ public class PackageAddedReceiver extends PackageReceiver { values.put(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName); values.put(InstalledAppProvider.DataColumns.APPLICATION_LABEL, InstalledAppProvider.getApplicationLabel(context, appId)); + values.put(InstalledAppProvider.DataColumns.SIGNATURE, + InstalledAppProvider.getPackageSig(info)); context.getContentResolver().insert(uri, values); } diff --git a/F-Droid/src/org/fdroid/fdroid/receiver/PackageReceiver.java b/F-Droid/src/org/fdroid/fdroid/receiver/PackageReceiver.java index 55cf84595..a3ca765ba 100644 --- a/F-Droid/src/org/fdroid/fdroid/receiver/PackageReceiver.java +++ b/F-Droid/src/org/fdroid/fdroid/receiver/PackageReceiver.java @@ -40,7 +40,7 @@ abstract class PackageReceiver extends BroadcastReceiver { protected PackageInfo getPackageInfo(Context context, String appId) { PackageInfo info = null; try { - info = context.getPackageManager().getPackageInfo(appId, 0); + info = context.getPackageManager().getPackageInfo(appId, PackageManager.GET_SIGNATURES); } catch (PackageManager.NameNotFoundException e) { // ignore } diff --git a/F-Droid/src/org/fdroid/fdroid/receiver/PackageUpgradedReceiver.java b/F-Droid/src/org/fdroid/fdroid/receiver/PackageUpgradedReceiver.java index dafc796d2..35d730b9e 100644 --- a/F-Droid/src/org/fdroid/fdroid/receiver/PackageUpgradedReceiver.java +++ b/F-Droid/src/org/fdroid/fdroid/receiver/PackageUpgradedReceiver.java @@ -59,6 +59,8 @@ public class PackageUpgradedReceiver extends PackageReceiver { values.put(InstalledAppProvider.DataColumns.VERSION_NAME, info.versionName); values.put(InstalledAppProvider.DataColumns.APPLICATION_LABEL, InstalledAppProvider.getApplicationLabel(context, appId)); + values.put(InstalledAppProvider.DataColumns.SIGNATURE, + InstalledAppProvider.getPackageSig(info)); context.getContentResolver().insert(uri, values); }