diff options
author | Philip P. Moltmann <moltmann@google.com> | 2016-10-13 10:16:29 -0700 |
---|---|---|
committer | Philip P. Moltmann <moltmann@google.com> | 2016-10-19 09:21:51 -0700 |
commit | 20c052885a756ffe4f8febc88e938fb43c5d5516 (patch) | |
tree | 0bc6f835242a63ba0403ef7e396e2aa4d0f9045f /src/com/android/packageinstaller/PackageInstallerActivity.java | |
parent | bf586567ae680659d3d7d224e5cfc5d71a9dc4c5 (diff) | |
download | android_packages_apps_PackageInstaller-20c052885a756ffe4f8febc88e938fb43c5d5516.tar.gz android_packages_apps_PackageInstaller-20c052885a756ffe4f8febc88e938fb43c5d5516.tar.bz2 android_packages_apps_PackageInstaller-20c052885a756ffe4f8febc88e938fb43c5d5516.zip |
Factor our staging step to own activity.
To make the Package Installer safe against acivity lifecyle I need to
make each installation step a separate activity. Also the activity's
with progress (staging, installation-progress) have to be carefully
crafted to work correctly with the activity lifecycle.
There will be further changed dealing with the other steps.
Test: Installed from content-URI
Forced staging to fail and checked that dialog works
Canceled staging via cancel button
Change-Id: I914fad6898f9ed9c71f18370811dca1986040561
Diffstat (limited to 'src/com/android/packageinstaller/PackageInstallerActivity.java')
-rw-r--r-- | src/com/android/packageinstaller/PackageInstallerActivity.java | 170 |
1 files changed, 36 insertions, 134 deletions
diff --git a/src/com/android/packageinstaller/PackageInstallerActivity.java b/src/com/android/packageinstaller/PackageInstallerActivity.java index d2dea723..4c453d08 100644 --- a/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -32,9 +32,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.VerificationParams; -import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Process; @@ -48,16 +46,10 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AppSecurityPermissions; import android.widget.Button; -import android.widget.ImageView; import android.widget.TabHost; import android.widget.TextView; -import com.android.packageinstaller.permission.utils.Utils; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; /* * This activity is launched when a new application is installed via side loading @@ -78,14 +70,13 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen private static final String SCHEME_CONTENT = "content"; private static final String SCHEME_PACKAGE = "package"; + private static final String EXTRA_ORIGINAL_SOURCE_INFO = "EXTRA_ORIGINAL_SOURCE_INFO"; + private int mSessionId = -1; private Uri mPackageURI; private Uri mOriginatingURI; private Uri mReferrerURI; private int mOriginatingUid = VerificationParams.NO_UID; - private File mContentUriApkStagingFile; - - private AsyncTask<Uri, Void, File> mStagingAsynTask; private boolean localLOGV = false; PackageManager mPm; @@ -307,7 +298,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { setResult(RESULT_OK); - clearCachedApkIfNeededAndFinish(); + finish(); } }) .setOnCancelListener(this) @@ -329,7 +320,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen if (request == REQUEST_ENABLE_UNKNOWN_SOURCES && result == RESULT_OK) { checkIfAllowedAndInitiateInstall(true); } else { - clearCachedApkIfNeededAndFinish(); + finish(); } } @@ -337,16 +328,12 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen String callerPackage = getCallingPackage(); if (callerPackage != null && intent.getBooleanExtra( Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) { - try { - mSourceInfo = mPm.getApplicationInfo(callerPackage, 0); - if (mSourceInfo != null) { - if ((mSourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) - != 0) { - // Privileged apps are not considered an unknown source. - return false; - } + if (mSourceInfo != null) { + if ((mSourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) + != 0) { + // Privileged apps are not considered an unknown source. + return false; } - } catch (NameNotFoundException e) { } } @@ -411,6 +398,15 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); final Intent intent = getIntent(); + + // This activity might have been started by InstallStaging. In this case recover + // the info from the app that initiated the install request + if (getPackageName().equals(getCallingPackage())) { + mSourceInfo = getIntent().getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO); + } else { + mSourceInfo = getSourceInfo(); + } + mOriginatingUid = getOriginatingUid(intent); final Uri packageUri; @@ -492,7 +488,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen } } else { startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)); - clearCachedApkIfNeededAndFinish(); + finish(); } } else if (!isUnknownSourcesEnabled() && isManagedProfile) { showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES); @@ -510,10 +506,6 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen @Override protected void onDestroy() { - if (mStagingAsynTask != null) { - mStagingAsynTask.cancel(true); - mStagingAsynTask = null; - } super.onDestroy(); } @@ -567,15 +559,24 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen } break; case SCHEME_CONTENT: { - mStagingAsynTask = new StagingAsyncTask(); - mStagingAsynTask.execute(packageUri); + Intent installStaging = new Intent(getIntent()); + installStaging.setClass(this, InstallStaging.class); + + // Store UID which might not be set in original intent + installStaging.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid); + + // Store source info as when called back the source is the packageinstaller + installStaging.putExtra(EXTRA_ORIGINAL_SOURCE_INFO, mSourceInfo); + installStaging.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); + startActivity(installStaging); + finish(); return false; } default: { Log.w(TAG, "Unsupported scheme " + scheme); setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); - clearCachedApkIfNeededAndFinish(); + finish(); return false; } } @@ -609,8 +610,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen // Get the source info from the calling package, if available. This will be the // definitive calling package, but it only works if the intent was started using // startActivityForResult, - ApplicationInfo sourceInfo = getSourceInfo(); - if (sourceInfo != null) { + if (mSourceInfo != null) { if (uidFromIntent != VerificationParams.NO_UID && (mSourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) { return uidFromIntent; @@ -618,7 +618,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen } // We either didn't get a uid in the intent, or we don't trust it. Use the // uid of the calling package instead. - return sourceInfo.uid; + return mSourceInfo.uid; } // We couldn't get the specific calling package. Let's get the uid instead @@ -667,7 +667,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen // Generic handling when pressing back key public void onCancel(DialogInterface dialog) { - clearCachedApkIfNeededAndFinish(); + finish(); } public void onClick(View v) { @@ -675,7 +675,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen if (mOkCanInstall || mScrollView == null) { if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, true); - clearCachedApkIfNeededAndFinish(); + finish(); } else { startInstall(); } @@ -688,7 +688,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, false); } - clearCachedApkIfNeededAndFinish(); + finish(); } } @@ -722,102 +722,4 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen startActivity(newIntent); finish(); } - - private void clearCachedApkIfNeededAndFinish() { - if (mContentUriApkStagingFile != null) { - mContentUriApkStagingFile.delete(); - mContentUriApkStagingFile = null; - } - finish(); - } - - private final class StagingAsyncTask extends AsyncTask<Uri, Void, File> { - private static final long SHOW_EMPTY_STATE_DELAY_MILLIS = 300; - - private final Runnable mEmptyStateRunnable = new Runnable() { - @Override - public void run() { - ((TextView) findViewById(R.id.app_name)).setText(R.string.app_name_unknown); - ((TextView) findViewById(R.id.install_confirm_question)) - .setText(R.string.message_staging); - mInstallConfirm.setVisibility(View.VISIBLE); - findViewById(android.R.id.tabhost).setVisibility(View.INVISIBLE); - findViewById(R.id.spacer).setVisibility(View.VISIBLE); - findViewById(R.id.ok_button).setEnabled(false); - Drawable icon = getDrawable(R.drawable.ic_file_download); - Utils.applyTint(PackageInstallerActivity.this, - icon, android.R.attr.colorControlNormal); - ((ImageView) findViewById(R.id.app_icon)).setImageDrawable(icon); - } - }; - - @Override - protected void onPreExecute() { - getWindow().getDecorView().postDelayed(mEmptyStateRunnable, - SHOW_EMPTY_STATE_DELAY_MILLIS); - } - - @Override - protected File doInBackground(Uri... params) { - if (params == null || params.length <= 0) { - return null; - } - Uri packageUri = params[0]; - File sourceFile = null; - try { - sourceFile = File.createTempFile("package", ".apk", getCacheDir()); - try ( - InputStream in = getContentResolver().openInputStream(packageUri); - OutputStream out = (in != null) ? new FileOutputStream( - sourceFile) : null; - ) { - // Despite the comments in ContentResolver#openInputStream - // the returned stream can be null. - if (in == null) { - return null; - } - byte[] buffer = new byte[4096]; - int bytesRead; - while ((bytesRead = in.read(buffer)) >= 0) { - // Be nice and respond to a cancellation - if (isCancelled()) { - return null; - } - out.write(buffer, 0, bytesRead); - } - } - } catch (IOException | SecurityException e) { - Log.w(TAG, "Error staging apk from content URI", e); - if (sourceFile != null) { - sourceFile.delete(); - } - } - return sourceFile; - } - - @Override - protected void onPostExecute(File file) { - getWindow().getDecorView().removeCallbacks(mEmptyStateRunnable); - if (isFinishing() || isDestroyed()) { - return; - } - if (file == null) { - showDialogInner(DLG_PACKAGE_ERROR); - setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); - return; - } - mContentUriApkStagingFile = file; - Uri fileUri = Uri.fromFile(file); - - boolean wasSetUp = processPackageUri(fileUri); - if (wasSetUp) { - checkIfAllowedAndInitiateInstall(false); - } - } - - @Override - protected void onCancelled(File file) { - getWindow().getDecorView().removeCallbacks(mEmptyStateRunnable); - } - }; } |