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.
This commit is contained in:
parent
bb9426763c
commit
eefbee969e
@ -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);
|
||||
}
|
||||
|
@ -100,6 +100,8 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
|
||||
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<App> {
|
||||
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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<String, Integer> cachedInfo = InstalledAppProvider.Helper.all(context);
|
||||
|
||||
List<PackageInfo> installedPackages = context.getPackageManager().getInstalledPackages(0);
|
||||
List<PackageInfo> 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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user