Merge branch 'installed-sig' into 'master'
Cache installed signature This will later be useful for #122 and others. Also a few more fixes related to signatures and package information. CC @pserwylo See merge request !158
This commit is contained in:
commit
3df93940c8
@ -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