Installer: handle package parse errors, fixes #395

This commit is contained in:
Daniel Martí 2015-09-03 18:52:40 -07:00
parent 74c93907c5
commit 10171d9228
6 changed files with 102 additions and 68 deletions

View File

@ -295,6 +295,7 @@
<string name="update_all">Update all</string>
<string name="install_error_title">Install error</string>
<string name="install_error_unknown">Failed to install due to an unknown error</string>
<string name="install_error_cannot_parse">An error occurred while parsing the package</string>
<string name="uninstall_error_title">Uninstall error</string>
<string name="uninstall_error_unknown">Failed to uninstall due to an unknown error</string>
<string name="system_permission_denied_title">System permissions denied</string>

View File

@ -909,15 +909,20 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
final int title, body;
if (operation == InstallerCallback.OPERATION_INSTALL) {
title = R.string.install_error_title;
} else {
title = R.string.uninstall_error_title;
}
switch (errorCode) {
default:
if (operation == InstallerCallback.OPERATION_INSTALL) {
case ERROR_CODE_CANNOT_PARSE:
body = R.string.install_error_cannot_parse;
break;
default: // ERROR_CODE_OTHER
body = R.string.install_error_unknown;
} else {
body = R.string.uninstall_error_unknown;
break;
}
} else { // InstallerCallback.OPERATION_DELETE
title = R.string.uninstall_error_title;
switch (errorCode) {
default: // ERROR_CODE_OTHER
body = R.string.install_error_unknown;
break;
}
}
runOnUiThread(new Runnable() {

View File

@ -36,6 +36,15 @@ public class AppDiff {
final String pkgPath = mPackageURI.getPath();
mPkgInfo = mPm.getPackageArchiveInfo(pkgPath, PackageManager.GET_PERMISSIONS);
// We could not get the package info from the file. This means that we
// could not parse the file, which can happen if the file cannot be
// read or the minSdk is not satisfied.
// Since we can't return an error from a constructor, we refuse to
// continue. The caller must check if mPkgInfo is null to see if the
// AppDiff was initialised correctly.
if (mPkgInfo == null) {
return;
}
mPkgInfo.applicationInfo.sourceDir = pkgPath;
mPkgInfo.applicationInfo.publicSourceDir = pkgPath;

View File

@ -43,6 +43,8 @@ import org.fdroid.fdroid.R;
public class InstallConfirmActivity extends Activity implements OnCancelListener, OnClickListener {
public static final int RESULT_CANNOT_PARSE = RESULT_FIRST_USER + 1;
private Intent intent;
PackageManager mPm;
@ -83,7 +85,6 @@ public class InstallConfirmActivity extends Activity implements OnCancelListener
mScrollView = null;
mOkCanInstall = false;
int msg = 0;
if (mAppDiff.mPkgInfo != null) {
AppSecurityPermissions perms = new AppSecurityPermissions(this, mAppDiff.mPkgInfo);
final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL);
final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE);
@ -131,7 +132,7 @@ public class InstallConfirmActivity extends Activity implements OnCancelListener
adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator(
getText(R.string.allPerms)), root);
}
}
if (!permVisible) {
if (mAppDiff.mInstalledAppInfo != null) {
// This is an update to an application, but there are no
@ -184,6 +185,10 @@ public class InstallConfirmActivity extends Activity implements OnCancelListener
Uri packageURI = intent.getData();
mAppDiff = new AppDiff(mPm, packageURI);
if (mAppDiff.mPkgInfo == null) {
setResult(RESULT_CANNOT_PARSE, intent);
finish();
}
setContentView(R.layout.install_start);
mInstallConfirm = findViewById(R.id.install_confirm_panel);

View File

@ -78,8 +78,10 @@ abstract public class Installer {
int OPERATION_INSTALL = 1;
int OPERATION_DELETE = 2;
int ERROR_CODE_CANCELED = 1;
int ERROR_CODE_OTHER = 2;
// Avoid using [-1,1] as they may conflict with Activity.RESULT_*
int ERROR_CODE_CANCELED = 2;
int ERROR_CODE_OTHER = 3;
int ERROR_CODE_CANNOT_PARSE = 4;
void onSuccess(int operation);

View File

@ -140,7 +140,13 @@ public class SystemInstaller extends Installer {
@Override
protected void installPackageInternal(File apkFile) throws AndroidNotCompatibleException {
Uri packageUri = Uri.fromFile(apkFile);
if (hasNewPermissions(packageUri)) {
int count = newPermissionCount(packageUri);
if (count < 0) {
mCallback.onError(InstallerCallback.OPERATION_INSTALL,
InstallerCallback.ERROR_CODE_CANNOT_PARSE);
return;
}
if (count > 0) {
Intent intent = new Intent(mContext, InstallConfirmActivity.class);
intent.setData(packageUri);
mActivity.startActivityForResult(intent, REQUEST_CONFIRM_PERMS);
@ -154,17 +160,20 @@ public class SystemInstaller extends Installer {
}
}
private boolean hasNewPermissions(Uri packageUri) {
private int newPermissionCount(Uri packageUri) {
AppDiff appDiff = new AppDiff(mContext.getPackageManager(), packageUri);
if (appDiff.mPkgInfo != null) {
if (appDiff.mPkgInfo == null) {
// could not get diff because we couldn't parse the package
return -1;
}
AppSecurityPermissions perms = new AppSecurityPermissions(mContext, appDiff.mPkgInfo);
if (appDiff.mInstalledAppInfo != null) { // it is an update to an existing app
// return false if there are no new permissions
return (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
if (appDiff.mInstalledAppInfo != null) {
// update to an existing app
return perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW);
}
}
// default: show install confirm activity
return true;
// default: even if there aren't any permissions, we want to make the
// user always confirm installing new apps
return 1;
}
private void doInstallPackageInternal(Uri packageURI) throws AndroidNotCompatibleException {
@ -260,7 +269,10 @@ public class SystemInstaller extends Installer {
mCallback.onError(InstallerCallback.OPERATION_INSTALL,
InstallerCallback.ERROR_CODE_OTHER);
}
} else {
} else if (resultCode == InstallConfirmActivity.RESULT_CANNOT_PARSE) {
mCallback.onError(InstallerCallback.OPERATION_INSTALL,
InstallerCallback.ERROR_CODE_CANNOT_PARSE);
} else { // Activity.RESULT_CANCELED
mCallback.onError(InstallerCallback.OPERATION_INSTALL,
InstallerCallback.ERROR_CODE_CANCELED);
}