Android_PackageInstall源码

PackageInstall
阅读packageInstall源码我们的突破口是从程序的窗口开始,首先查看AndroidManifest文件中activity的定义
PackageInstallerActivity: 
    窗口指定了两个IntentFilter,因此两种方式调用该窗口,两种方式都定义了action: android.intent.action.INSTALL_PACKAGE,第一种方式需要在apk文件路径前加"file:"而且扩展名必须为apk,这个现实由android:mimeType决定,而第二种方式除了加"file:"前缀,还可以加"package:"前缀,对扩展名没有限制
UninstallerActivity:
    只有一个IntentFilter,并且指定了两个action,在卸载应用程序时,指定哪一个action都可以,除此之外,还需要卸载程序的package,并且package必须加"package:"前缀
InstallAppProgressUninstallerActivity没有定义任何action,因此无法被其他应用调用
这个四个activity都没有指定  android.intent.action.MAIN所以在程序列表中是没有图标的,PackageInstallerActivity和InstallAppProgress用于安装应用程序,UninstallerActivity和UninstallerActivity用于卸载应用程序(如果activity定义了action为MAIN,category为LAUNCHER,就会出现多个应用程序图标启动对应activity)
安装apk:   通过指定apk文件的绝对路径安装
    Intent intent=new Intent(Intent.ACTION_INSTALL_PACKAGE);  
    intent.setDataAndType(Uri.fromFile(new File("/ascard/qq.apk")),"application/vnd.android.package-archive");    //满足第一个IntentFilter
// intent.setData(Uri.fromFile(new File("/sdcard/qq.apk")));     //满足第二个IntentFilter(没有指定MimeType)
    startActivity(intent);
安装apk:    如果通过package方式安装,前提是该应用已经安装,也就是这种事方式是升级应用,如果未安装该应用,会弹出错误提示框
    Intent intent=new Intent(Intent.ACTION_INSTALL_PACKAGE);
    intent.setData(Uri.parse("package:com.tencent.mobileqq"));
    startActivity(intent);
卸载apk:   卸载apk只有一种方式,需要指定卸载应用的package,不过有两个可以设置的action
    Intent intent=new Intent(Intent.ACTION_DELETE);
// Intent intent=new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
    intent.setData(Uri.parse("package:com.tencent.mobileqq"));
    startActivity(intent);
应用程序安装源码:
<span style="color:#666666">package com.android.packageinstaller;
/*
 * This activity is launched when a new application is installed via side loading
 * The package is first parsed and the user is notified of parse errors via a dialog.
 * If the package is successfully parsed, the user is notified to turn on the install unknown
 * applications setting. A memory check is made at this point and the user is notified of out
 * of memory conditions if any. If the package is already existing on the device, 
 * a confirmation dialog (to replace the existing package) is presented to the user.
 * Based on the user response the package is then installed by launching InstallAppConfirm
 * sub activity. All state transitions are handled in this activity
 */
public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener {
private static final String TAG = "PackageInstaller";

private int mSessionId = -1;
private Uri mPackageURI;    
private Uri mOriginatingURI;
private Uri mReferrerURI;
private int mOriginatingUid = VerificationParams.NO_UID;
private ManifestDigest mPkgDigest;

private boolean localLOGV = false;
    PackageManager mPm;
    PackageInstaller mInstaller;
    PackageInfo mPkgInfo;
    ApplicationInfo mSourceInfo;

// ApplicationInfo object primarily used for already existing applications
private ApplicationInfo mAppInfo = null;

private InstallFlowAnalytics mInstallFlowAnalytics;

// View for install progress
View mInstallConfirm;
// Buttons to indicate user acceptance
private Button mOk;
private Button mCancel;
    CaffeinatedScrollView mScrollView = null;
private boolean mOkCanInstall = false;

static final String PREFS_ALLOWED_SOURCES = "allowed_sources";

private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";

private static final String TAB_ID_ALL = "all";
private static final String TAB_ID_NEW = "new";

// Dialog identifiers used in showDialog
private static final int DLG_BASE = 0;
private static final int DLG_UNKNOWN_APPS = DLG_BASE + 1;
private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2;
private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3;
private static final int DLG_INSTALL_ERROR = DLG_BASE + 4;
private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5;

private void startInstallConfirm() {
        TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
        tabHost.setup();
        ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
        TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager);
        adapter.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
@Override
public void onTabChanged(String tabId) {
if (TAB_ID_ALL.equals(tabId)) {
mInstallFlowAnalytics.setAllPermissionsDisplayed(true);
                } else if (TAB_ID_NEW.equals(tabId)) {
mInstallFlowAnalytics.setNewPermissionsDisplayed(true);
                }
            }
        });

boolean permVisible = false;    //  true: 显示权限列表  false: 未显示权限列表
mScrollView = null;
mOkCanInstall = false;
int msg = 0;
if (mPkgInfo != null) {
            AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
//  获取隐私相关权限的数量
final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL);
//  获取与设备相关权限的数量
final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE);
if (mAppInfo != null) {
//  判断是否为系统应用,并使用不同的布局文件
msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
? R.string.install_confirm_question_update_system
                        : R.string.install_confirm_question_update;
mScrollView = new CaffeinatedScrollView(this);  //用来显示权限列表的滚动View
                //  如果显示的内容超过mScrollView,就会折叠可以滚动
mScrollView.setFillViewport(true);
boolean newPermissionsFound =
                        (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
mInstallFlowAnalytics.setNewPermissionsFound(newPermissionsFound);
//                针对更新应用程序相对旧版本而已判断是否加入了新的权限
if (newPermissionsFound) {
                    permVisible = true;
//  将新的权限列表视频添加到滚动视图中
mScrollView.addView(perms.getPermissionsView(
                            AppSecurityPermissions.WHICH_NEW));
                } else {    //  没有设置任何权限,只显示应用程序名称和图标
LayoutInflater inflater = (LayoutInflater)getSystemService(
                            Context.LAYOUT_INFLATER_SERVICE);
                    TextView label = (TextView)inflater.inflate(R.layout.label, null);
                    label.setText(R.string.no_new_perms);
mScrollView.addView(label);
                }
                adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator(
                        getText(R.string.newPerms)), mScrollView);
            } else  {   //  无法获取应用的任何信息,将相应的控件隐藏
findViewById(R.id.tabscontainer).setVisibility(View.GONE);
                findViewById(R.id.divider).setVisibility(View.VISIBLE);
            }
//  如果至少设置了一个权限
if (NP > 0 || ND > 0) {
                permVisible = true;
                LayoutInflater inflater = (LayoutInflater)getSystemService(
                        Context.LAYOUT_INFLATER_SERVICE);
                View root = inflater.inflate(R.layout.permissions_list, null);
if (mScrollView == null) {
mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview);
                }
//  有与隐私相关的权限
if (NP > 0) {
//  在滚动视图上显示与隐私相关的权限
((ViewGroup)root.findViewById(R.id.privacylist)).addView(
                            perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL));
                } else {
                    root.findViewById(R.id.privacylist).setVisibility(View.GONE);
                }
//  有与设备相关的权限
if (ND > 0) {
//  在滚动视图上显示与设备相关的权限
((ViewGroup)root.findViewById(R.id.devicelist)).addView(
                            perms.getPermissionsView(AppSecurityPermissions.WHICH_DEVICE));
                } else {
                    root.findViewById(R.id.devicelist).setVisibility(View.GONE);
                }
                adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator(
                        getText(R.string.allPerms)), root);
            }
        }
mInstallFlowAnalytics.setPermissionsDisplayed(permVisible);
//  没有任何权限
if (!permVisible) {
if (mAppInfo != null) {
// This is an update to an application, but there are no
                // permissions at all.
msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
? R.string.install_confirm_question_update_system_no_perms
                        : R.string.install_confirm_question_update_no_perms;
            } else {
// This is a new application with no permissions.
msg = R.string.install_confirm_question_no_perms;
            }
            tabHost.setVisibility(View.GONE);
mInstallFlowAnalytics.setAllPermissionsDisplayed(false);
mInstallFlowAnalytics.setNewPermissionsDisplayed(false);
            findViewById(R.id.filler).setVisibility(View.VISIBLE);
            findViewById(R.id.divider).setVisibility(View.GONE);
mScrollView = null;
        }
if (msg != 0) {
            ((TextView)findViewById(R.id.install_confirm_question)).setText(msg);
        }
//    mInstallConfirm为显示权限列表的最顶层视图
mInstallConfirm.setVisibility(View.VISIBLE);
mOk = (Button)findViewById(R.id.ok_button);
mCancel = (Button)findViewById(R.id.cancel_button);
mOk.setOnClickListener(this);
mCancel.setOnClickListener(this);
if (mScrollView == null) {
// There is nothing to scroll view, so the ok button is immediately
            // set to install.
            //  应用程序没有任何权限,直接将按钮设为"安装"
mOk.setText(R.string.install);
mOkCanInstall = true;
        } else {
//  显示权限列表是,当滚动到最后是,将按钮设置为"安装",否则是"下一步"
mScrollView.setFullScrollAction(new Runnable() {
@Override
public void run() {
mOk.setText(R.string.install);
mOkCanInstall = true;
                }
            });
        }
    }

private void showDialogInner(int id) {
// TODO better fix for this? Remove dialog so that it gets created again
removeDialog(id);
        showDialog(id);
    }

@Override
public Dialog onCreateDialog(int id, Bundle bundle) {
switch (id) {
case DLG_UNKNOWN_APPS:
return new AlertDialog.Builder(this)
                    .setTitle(R.string.unknown_apps_dlg_title)
                    .setMessage(R.string.unknown_apps_dlg_text)
                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
                            Log.i(TAG, "Finishing off activity so that user can navigate to settings manually");
                            finish();
                        }})
                    .setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
                            Log.i(TAG, "Launching settings");
                            launchSettingsAppAndFinish();
                        }
                    })
                    .setOnCancelListener(this)
                    .create(); 
case DLG_PACKAGE_ERROR :
return new AlertDialog.Builder(this)
                    .setTitle(R.string.Parse_error_dlg_title)
                    .setMessage(R.string.Parse_error_dlg_text)
                    .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
                            finish();
                        }
                    })
                    .setOnCancelListener(this)
                    .create();
case DLG_OUT_OF_SPACE:
// Guaranteed not to be null. will default to package name if not set by app
CharSequence appTitle = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
            String dlgText = getString(R.string.out_of_space_dlg_text, 
                    appTitle.toString());
return new AlertDialog.Builder(this)
                    .setTitle(R.string.out_of_space_dlg_title)
                    .setMessage(dlgText)
                    .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//launch manage applications
Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
                            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);   
                            finish();
                        }
                    })
                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
                            Log.i(TAG, "Canceling installation");
                            finish();
                        }
                  })
                  .setOnCancelListener(this)
                  .create();
case DLG_INSTALL_ERROR :
// Guaranteed not to be null. will default to package name if not set by app
CharSequence appTitle1 = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
            String dlgText1 = getString(R.string.install_failed_msg,
                    appTitle1.toString());
return new AlertDialog.Builder(this)
                    .setTitle(R.string.install_failed)
                    .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
                            finish();
                        }
                    })
                    .setMessage(dlgText1)
                    .setOnCancelListener(this)
                    .create();
case DLG_ALLOW_SOURCE:
            CharSequence appTitle2 = mPm.getApplicationLabel(mSourceInfo);
            String dlgText2 = getString(R.string.allow_source_dlg_text,
                    appTitle2.toString());
return new AlertDialog.Builder(this)
                    .setTitle(R.string.allow_source_dlg_title)
                    .setMessage(dlgText2)
                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
                            setResult(RESULT_CANCELED);
                            finish();
                        }})
                    .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
                            SharedPreferences prefs = getSharedPreferences(PREFS_ALLOWED_SOURCES,
                                    Context.MODE_PRIVATE);
                            prefs.edit().putBoolean(mSourceInfo.packageName, true).apply();
                            startInstallConfirm();
                        }
                    })
                    .setOnCancelListener(this)
                    .create();
       }
return null;
   }

private void launchSettingsAppAndFinish() {
// Create an intent to launch SettingsTwo activity
Intent launchSettingsIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
        launchSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(launchSettingsIntent);
        finish();
    }

private boolean isInstallingUnknownAppsAllowed() {
        UserManager um = (UserManager) getSystemService(USER_SERVICE);

boolean disallowedByUserManager = um.getUserRestrictions()
                .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, false);
//  获取contentProvider中"未知来源"是否选中来判断
        //  执行这句代码没有添加任何权限,但是前提是对apk进行系统签名,也就是说必须和源码一起编译或者使用mm/mmm命令单独进行编译
        // 普通安装应用尽管编译能通过,但是执行到这里的时候回报错
boolean allowedBySecureSettings = Settings.Secure.getInt(getContentResolver(),
            Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;

return (allowedBySecureSettings && (!disallowedByUserManager));
    }

private boolean isInstallRequestFromUnknownSource(Intent intent) {
        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.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
// Privileged apps are not considered an unknown source.
return false;
                    }
                }
            } catch (NameNotFoundException e) {
            }
        }

return true;
    }

private boolean isVerifyAppsEnabled() {
        UserManager um = (UserManager) getSystemService(USER_SERVICE);
if (um.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS)) {
return true;
        }
return Settings.Global.getInt(getContentResolver(),
                Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) > 0;
    }

private boolean isAppVerifierInstalled() {
final PackageManager pm = getPackageManager();
final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
        verification.setType(PACKAGE_MIME_TYPE);
        verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0);
return (receivers.size() > 0) ? true : false;
    }

private void initiateInstall() {
        String pkgName = mPkgInfo.packageName;
// Check if there is already a package on the device with this name
        // but it has been renamed to something else.
String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
            pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
        }
// Check if package is already installed. display confirmation dialog if replacing pkg
try {
// This is a little convoluted because we want to get all uninstalled
            // apps, but this may include apps with just data, and if it is just
            // data we still want to count it as "installed".
mAppInfo = mPm.getApplicationInfo(pkgName,
                    PackageManager.GET_UNINSTALLED_PACKAGES);
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
            }
        } catch (NameNotFoundException e) {
mAppInfo = null;
        }

mInstallFlowAnalytics.setReplace(mAppInfo != null);
mInstallFlowAnalytics.setSystemApp(
                (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0));

        startInstallConfirm();//    显示一个确认对话框,安装的核心代码
}

void setPmResult(int pmResult) {
        Intent result = new Intent();
        result.putExtra(Intent.EXTRA_INSTALL_RESULT, pmResult);
        setResult(pmResult == PackageManager.INSTALL_SUCCEEDED
                ? RESULT_OK : RESULT_FIRST_USER, result);
    }

@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);

mPm = getPackageManager();
mInstaller = mPm.getPackageInstaller();

final Intent intent = getIntent();
if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
                Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
                finish();
return;
            }

mSessionId = sessionId;
mPackageURI = Uri.fromFile(new File(info.resolvedBaseCodePath));
mOriginatingURI = null;
mReferrerURI = null;
        } else {
mSessionId = -1;
mPackageURI = intent.getData();
mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
        }

boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
mInstallFlowAnalytics = new InstallFlowAnalytics();
mInstallFlowAnalytics.setContext(this);
mInstallFlowAnalytics.setStartTimestampMillis(SystemClock.elapsedRealtime());
mInstallFlowAnalytics.setInstallsFromUnknownSourcesPermitted(
                isInstallingUnknownAppsAllowed());
mInstallFlowAnalytics.setInstallRequestFromUnknownSource(requestFromUnknownSource);
mInstallFlowAnalytics.setVerifyAppsEnabled(isVerifyAppsEnabled());
mInstallFlowAnalytics.setAppVerifierInstalled(isAppVerifierInstalled());
mInstallFlowAnalytics.setPackageUri(mPackageURI.toString());

final String scheme = mPackageURI.getScheme();
if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
            Log.w(TAG, "Unsupported scheme " + scheme);
            setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
mInstallFlowAnalytics.setFlowFinished(
                    InstallFlowAnalytics.RESULT_FAILED_UNSUPPORTED_SCHEME);
            finish();
return;
        }

final PackageUtil.AppSnippet as;
//  处理scheme为package的情况
if ("package".equals(mPackageURI.getScheme())) {
mInstallFlowAnalytics.setFileUri(false);
try {
//  获取package对应的Android应用信息,如应用名称,权限列表..
mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(),
                        PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES);
            } catch (NameNotFoundException e) {
            }
//  如果无法获取,则弹出一个错误提示框,然后退出安装
if (mPkgInfo == null) {
                Log.w(TAG, "Requested package " + mPackageURI.getScheme()
                        + " not available. Discontinuing installation");
                showDialogInner(DLG_PACKAGE_ERROR);
                setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
mInstallFlowAnalytics.setPackageInfoObtained();
mInstallFlowAnalytics.setFlowFinished(
                        InstallFlowAnalytics.RESULT_FAILED_PACKAGE_MISSING);
return;
            }
//  创建AppSnippet对象,该对象封装了用于待安装Android应用的标题和图标
as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),
mPm.getApplicationIcon(mPkgInfo.applicationInfo));
        } else {        //  处理scheme为 file 的情况
mInstallFlowAnalytics.setFileUri(true);
//  获取apk文件的实际路径
final File sourceFile = new File(mPackageURI.getPath());
//  创建apk文件的分析器
PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);
// Check for parse errors
            //  如果无法创建文件分析器,则直接退出,弹出对话框
if (parsed == null) {
                Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
                showDialogInner(DLG_PACKAGE_ERROR);
                setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
mInstallFlowAnalytics.setPackageInfoObtained();
mInstallFlowAnalytics.setFlowFinished(
                        InstallFlowAnalytics.RESULT_FAILED_TO_GET_PACKAGE_INFO);
return;
            }
//  获取apk文件的相关信息
mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
                    PackageManager.GET_PERMISSIONS, 0, 0, null,
new PackageUserState());
mPkgDigest = parsed.manifestDigest;
//  另一种创建APPSnippet的方式,使用更好的方式提取应用程序名称和图标
as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
        }
mInstallFlowAnalytics.setPackageInfoObtained();
//  设置activity的视图
        //set view
setContentView(R.layout.install_start);
mInstallConfirm = findViewById(R.id.install_confirm_panel);
mInstallConfirm.setVisibility(View.INVISIBLE);
//  创建显示应用名称(TextView)和图标(ImageView)的控件
PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
//  获取应用的ID 对于普通应用,该值没有什么作用
mOriginatingUid = getOriginatingUid(intent);
//  判断系统是否允许安装未知来源的应用
        // Block the install attempt on the Unknown Sources setting if necessary.
if ((requestFromUnknownSource) && (!isInstallingUnknownAppsAllowed())) {
//ask user to enable setting first
            //  询问是否通过设置打开"未知来源"
showDialogInner(DLG_UNKNOWN_APPS);
mInstallFlowAnalytics.setFlowFinished(
                    InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
return;
        }
//  初始化安装
initiateInstall();
    }

/** Get the ApplicationInfo for the calling package, if available */
private ApplicationInfo getSourceInfo() {
        String callingPackage = getCallingPackage();
if (callingPackage != null) {
try {
return mPm.getApplicationInfo(callingPackage, 0);
            } catch (NameNotFoundException ex) {
// ignore
}
        }
return null;
    }


/** Get the originating uid if possible, or VerificationParams.NO_UID if not available */
private int getOriginatingUid(Intent intent) {
// The originating uid from the intent. We only trust/use this if it comes from a
        // system application
int uidFromIntent = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                VerificationParams.NO_UID);

// 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 (uidFromIntent != VerificationParams.NO_UID &&
                    (mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
return uidFromIntent;

            }
// 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;
        }

// We couldn't get the specific calling package. Let's get the uid instead
int callingUid;
try {
            callingUid = ActivityManagerNative.getDefault()
                    .getLaunchedFromUid(getActivityToken());
        } catch (android.os.RemoteException ex) {
            Log.w(TAG, "Could not determine the launching uid.");
// nothing else we can do
return VerificationParams.NO_UID;
        }

// If we got a uid from the intent, we need to verify that the caller is a
        // privileged system package before we use it
if (uidFromIntent != VerificationParams.NO_UID) {
            String[] callingPackages = mPm.getPackagesForUid(callingUid);
if (callingPackages != null) {
for (String packageName: callingPackages) {
try {
                        ApplicationInfo applicationInfo =
mPm.getApplicationInfo(packageName, 0);

if ((applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
return uidFromIntent;
                        }
                    } catch (NameNotFoundException ex) {
// ignore it, and try the next package
}
                }
            }
        }
// We either didn't get a uid from the intent, or we don't trust it. Use the
        // calling uid instead.
return callingUid;
    }

@Override
public void onBackPressed() {
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, false);
        }
mInstallFlowAnalytics.setFlowFinished(
                InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);
super.onBackPressed();
    }

// Generic handling when pressing back key
public void onCancel(DialogInterface dialog) {
        finish();
    }

public void onClick(View v) {
if(v == mOk) {
if (mOkCanInstall || mScrollView == null) {
mInstallFlowAnalytics.setInstallButtonClicked();
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, true);

// We're only confirming permissions, so we don't really know how the
                    // story ends; assume success.
mInstallFlowAnalytics.setFlowFinishedWithPackageManagerResult(
                            PackageManager.INSTALL_SUCCEEDED);
                } else {
// Start subactivity to actually install the application
                    //  执行安装事件时,首先会给Intent传递很多值给InstallAppProgress,对于普通的应用程序很多只都是null,
Intent newIntent = new Intent();
                    newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
//  设置要安装的URI
newIntent.setData(mPackageURI);
//  指定安装activity
newIntent.setClass(this, InstallAppProgress.class);
                    newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);
                    newIntent.putExtra(
                            InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics);
                    String installerPackageName = getIntent().getStringExtra(
                            Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
                        newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
                    }
if (mReferrerURI != null) {
                        newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
                    }
if (mOriginatingUid != VerificationParams.NO_UID) {
                        newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
                    }
if (installerPackageName != null) {
                        newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
                                installerPackageName);
                    }
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
                        newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
                        newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
                    }
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
                    startActivity(newIntent);
                }
                finish();
            } else {    //  点击"下一步"继续显示权限列表
mScrollView.pageScroll(View.FOCUS_DOWN);
            }
        } else if(v == mCancel) {   //  点击"取消"退出安装
            // Cancel and finish
setResult(RESULT_CANCELED);
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, false);
            }
mInstallFlowAnalytics.setFlowFinished(
                    InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);
            finish();
        }
    }
}
</span>
startInstallConfirm方法主要是通过getPermissionsView方法获取不同权限的View,并在滚动视图中显示这些view
AppSecurityPermissions.WHICH_NEW    新加入的权限
AppSecurityPermissions.WHICH_PERSONAL    与用户隐私相关的权限
AppSecurityPermissions.WHICH_DEVICE    与设备相关的权限
<span style="color:#666666">package com.android.packageinstaller;

/**
 * This activity corresponds to a download progress screen that is displayed 
 * when the user tries
 * to install an application bundled as an apk file. The result of the application install
 * is indicated in the result code that gets set to the corresponding installation status
 * codes defined in PackageManager. If the package being installed already exists,
 * the existing package is replaced with the new one.
 */
public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener {
private final String TAG="InstallAppProgress";
private boolean localLOGV = false;
static final String EXTRA_MANIFEST_DIGEST =
"com.android.packageinstaller.extras.manifest_digest";
static final String EXTRA_INSTALL_FLOW_ANALYTICS =
"com.android.packageinstaller.extras.install_flow_analytics";
private ApplicationInfo mAppInfo;
private Uri mPackageURI;
private InstallFlowAnalytics mInstallFlowAnalytics;
private ProgressBar mProgressBar;
private View mOkPanel;
private TextView mStatusTextView;
private TextView mExplanationTextView;
private Button mDoneButton;
private Button mLaunchButton;
private final int INSTALL_COMPLETE = 1;
private Intent mLaunchIntent;
private static final int DLG_OUT_OF_SPACE = 1;
private CharSequence mLabel;

private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case INSTALL_COMPLETE:  //成功安装
mInstallFlowAnalytics.setFlowFinishedWithPackageManagerResult(msg.arg1);
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
                        Intent result = new Intent();
result.putExtra(Intent.EXTRA_INSTALL_RESULT, msg.arg1);
                        setResult(msg.arg1 == PackageManager.INSTALL_SUCCEEDED
                                        ? Activity.RESULT_OK : Activity.RESULT_FIRST_USER,
result);
                        finish();
return;
                    }
// Update the status text
mProgressBar.setVisibility(View.INVISIBLE);
// Show the ok button
int centerTextLabel;
int centerExplanationLabel = -1;
                    LevelListDrawable centerTextDrawable = (LevelListDrawable) getResources()
                            .getDrawable(R.drawable.ic_result_status);
if (msg.arg1 == PackageManager.INSTALL_SUCCEEDED) {
mLaunchButton.setVisibility(View.VISIBLE);
                        centerTextDrawable.setLevel(0);
                        centerTextLabel = R.string.install_done;
// Enable or disable launch button
mLaunchIntent = getPackageManager().getLaunchIntentForPackage(
mAppInfo.packageName);
boolean enabled = false;
if(mLaunchIntent != null) {
                            List<ResolveInfo> list = getPackageManager().
                                    queryIntentActivities(mLaunchIntent, 0);
if (list != null && list.size() > 0) {
                                enabled = true;
                            }
                        }
if (enabled) {
//  该按钮用于打开已经安装成功的程序
mLaunchButton.setOnClickListener(InstallAppProgress.this);
                        } else {
mLaunchButton.setEnabled(false);
                        }
//  由于空间不足导致安装失败
} else if (msg.arg1 == PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE){
                        showDialogInner(DLG_OUT_OF_SPACE);
return;
                    } else {    //  由于其他原因导致安装失败
                        // Generic error handling for all other error codes.
centerTextDrawable.setLevel(1);
                        centerExplanationLabel = getExplanationFromErrorCode(msg.arg1);
                        centerTextLabel = R.string.install_failed;
mLaunchButton.setVisibility(View.INVISIBLE);
                    }
if (centerTextDrawable != null) {
                        centerTextDrawable.setBounds(0, 0,
                                centerTextDrawable.getIntrinsicWidth(),
                                centerTextDrawable.getIntrinsicHeight());
mStatusTextView.setCompoundDrawablesRelative(centerTextDrawable, null,
null, null);
                    }
mStatusTextView.setText(centerTextLabel);
if (centerExplanationLabel != -1) {
mExplanationTextView.setText(centerExplanationLabel);
mExplanationTextView.setVisibility(View.VISIBLE);
                    } else {
mExplanationTextView.setVisibility(View.GONE);
                    }
mDoneButton.setOnClickListener(InstallAppProgress.this);
mOkPanel.setVisibility(View.VISIBLE);
break;
default:
break;
            }
        }
    };

private int getExplanationFromErrorCode(int errCode) {
        Log.d(TAG, "Installation error code: " + errCode);
switch (errCode) {
case PackageManager.INSTALL_FAILED_INVALID_APK:
return R.string.install_failed_invalid_apk;
case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES:
return R.string.install_failed_inconsistent_certificates;
case PackageManager.INSTALL_FAILED_OLDER_SDK:
return R.string.install_failed_older_sdk;
case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE:
return R.string.install_failed_cpu_abi_incompatible;
default:
return -1;
        }
    }

@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
        Intent intent = getIntent();
//  获取待安装应用相关的值mAppInfo和mPackageURI
mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mInstallFlowAnalytics = intent.getParcelableExtra(EXTRA_INSTALL_FLOW_ANALYTICS);
mInstallFlowAnalytics.setContext(this);
mPackageURI = intent.getData();
//  验证scheme是否为file或package
final String scheme = mPackageURI.getScheme();
if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
mInstallFlowAnalytics.setFlowFinished(
                    InstallFlowAnalytics.RESULT_FAILED_UNSUPPORTED_SCHEME);
throw new IllegalArgumentException("unexpected scheme " + scheme);
        }
//  安装应用的核心代码
initView();
    }

@Override
public Dialog onCreateDialog(int id, Bundle bundle) {
switch (id) {
case DLG_OUT_OF_SPACE:
                String dlgText = getString(R.string.out_of_space_dlg_text, mLabel);
return new AlertDialog.Builder(this)
                        .setTitle(R.string.out_of_space_dlg_title)
                        .setMessage(dlgText)
                        .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//launch manage applications
Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
                                startActivity(intent);
                                finish();
                            }
                        })
                        .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
                                Log.i(TAG, "Canceling installation");
                                finish();
                            }
                        })
                        .setOnCancelListener(this)
                        .create();
        }
return null;
    }

private void showDialogInner(int id) {
        removeDialog(id);
        showDialog(id);
    }

class PackageInstallObserver extends IPackageInstallObserver.Stub {
public void packageInstalled(String packageName, int returnCode) {
//  该方法会在其他线程中调用,因此通过handler更新UI
Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
            msg.arg1 = returnCode;
mHandler.sendMessage(msg);
        }
    }

public void initView() {
        setContentView(R.layout.op_progress);
int installFlags = 0;
        PackageManager pm = getPackageManager();
try {
//  如果待安装的程序已经安装,返回PackageInfo对象,否则返回null
PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
                    PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null) {
//  如果应用已经安装,设置安装模式为更新
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
            }
        } catch (NameNotFoundException e) {
        }
if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
            Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
        }
final PackageUtil.AppSnippet as;
//  如果scheme为package,意味着更新程序
if ("package".equals(mPackageURI.getScheme())) {
            as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo),
                    pm.getApplicationIcon(mAppInfo));
        } else {    //  通过apk文件路径获取显示应用相关信息的视图
final File sourceFile = new File(mPackageURI.getPath());
            as = PackageUtil.getAppSnippet(this, mAppInfo, sourceFile);
        }
mLabel = as.label;
        PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
mStatusTextView = (TextView)findViewById(R.id.center_text);
mStatusTextView.setText(R.string.installing);
mExplanationTextView = (TextView) findViewById(R.id.center_explanation);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mProgressBar.setIndeterminate(true);
// Hide button till progress is being displayed
mOkPanel = (View)findViewById(R.id.buttons_panel);
mDoneButton = (Button)findViewById(R.id.done_button);
mLaunchButton = (Button)findViewById(R.id.launch_button);
mOkPanel.setVisibility(View.INVISIBLE);
//  获取待安装应用的package name
String installerPackageName = getIntent().getStringExtra(
                Intent.EXTRA_INSTALLER_PACKAGE_NAME);
//  对于普通的Android应用没下吗连个uri为null
Uri originatingURI = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
        Uri referrer = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);
int originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                VerificationParams.NO_UID);
        ManifestDigest manifestDigest = getIntent().getParcelableExtra(EXTRA_MANIFEST_DIGEST);
        VerificationParams verificationParams = new VerificationParams(null, originatingURI,
                referrer, originatingUid, manifestDigest);
//  安装成功,失败的监听
PackageInstallObserver observer = new PackageInstallObserver();
//  核心逻辑
if ("package".equals(mPackageURI.getScheme())) {
try {
//根据package name更新应用
pm.installExistingPackage(mAppInfo.packageName);
                observer.packageInstalled(mAppInfo.packageName,
                        PackageManager.INSTALL_SUCCEEDED);
            } catch (PackageManager.NameNotFoundException e) {
                observer.packageInstalled(mAppInfo.packageName,
                        PackageManager.INSTALL_FAILED_INVALID_APK);
            }
        } else {
//  安装或更新应用
pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
                    installerPackageName, verificationParams, null);
        }
    }

@Override
protected void onDestroy() {
super.onDestroy();
    }

public void onClick(View v) {
if(v == mDoneButton) {
if (mAppInfo.packageName != null) {
                Log.i(TAG, "Finished installing "+mAppInfo.packageName);
            }
            finish();
        } else if(v == mLaunchButton) {
            startActivity(mLaunchIntent);
            finish();
        }
    }

public void onCancel(DialogInterface dialog) {
        finish();
    }
}
</span>
PackageManager的installExistingPackage和installPackageWithVerificationAndEncryption都是静默安装,安装过程不会出现任何提示,不过这两个方法被设为hide,不能在普通Android应用中调用
查看源码发现安装过程中弹出的校验窗口是PackageInstaller有意展示的,同时Android的静默安装时通过如上方法实现的
应用程序卸载源码:
 
  
<span style="color:#666666">package com.android.packageinstaller; public class UninstallerActivity extends Activity { private static final String TAG = "UninstallerActivity"; public static class UninstallAlertDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final PackageManager pm = getActivity().getPackageManager(); final DialogInfo dialogInfo = ((UninstallerActivity) getActivity()).mDialogInfo; final CharSequence appLabel = dialogInfo.appInfo.loadLabel(pm); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity()); StringBuilder messageBuilder = new StringBuilder(); // If the Activity label differs from the App label, then make sure the user // knows the Activity belongs to the App being uninstalled. if (dialogInfo.activityInfo != null) { final CharSequence activityLabel = dialogInfo.activityInfo.loadLabel(pm); if (!activityLabel.equals(appLabel)) { messageBuilder.append( getString(R.string.uninstall_activity_text, activityLabel)); messageBuilder.append(" ").append(appLabel).append(".\n\n"); } } final boolean isUpdate = ((dialogInfo.appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0); if (isUpdate) { messageBuilder.append(getString(R.string.uninstall_update_text)); } else { UserManager userManager = UserManager.get(getActivity()); if (dialogInfo.allUsers && userManager.getUserCount() >= 2) { messageBuilder.append(getString(R.string.uninstall_application_text_all_users)); } else if (!dialogInfo.user.equals(android.os.Process.myUserHandle())) { UserInfo userInfo = userManager.getUserInfo(dialogInfo.user.getIdentifier()); messageBuilder.append( getString(R.string.uninstall_application_text_user, userInfo.name)); } else { messageBuilder.append(getString(R.string.uninstall_application_text)); } } dialogBuilder.setTitle(appLabel); dialogBuilder.setIcon(dialogInfo.appInfo.loadIcon(pm)); dialogBuilder.setPositiveButton(android.R.string.ok, this); dialogBuilder.setNegativeButton(android.R.string.cancel, this); dialogBuilder.setMessage(messageBuilder.toString()); return dialogBuilder.create(); } @Override public void onClick(DialogInterface dialog, int which) { if (which == Dialog.BUTTON_POSITIVE) { // 开始卸载应用 ((UninstallerActivity) getActivity()).startUninstallProgress(); } else { // 取消 ((UninstallerActivity) getActivity()).dispatchAborted(); } } @Override public void onDismiss(DialogInterface dialog) { super.onDismiss(dialog); getActivity().finish(); } } public static class AppNotFoundDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new AlertDialog.Builder(getActivity()) .setTitle(R.string.app_not_found_dlg_title) .setMessage(R.string.app_not_found_dlg_text) .setNeutralButton(android.R.string.ok, null) .create(); } @Override public void onDismiss(DialogInterface dialog) { super.onDismiss(dialog); ((UninstallerActivity) getActivity()).dispatchAborted(); getActivity().setResult(Activity.RESULT_FIRST_USER); getActivity().finish(); } } static class DialogInfo { ApplicationInfo appInfo; ActivityInfo activityInfo; boolean allUsers; UserHandle user; IBinder callback; } private DialogInfo mDialogInfo; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); // Get intent information. // We expect an intent with URI of the form package://<packageName>#<className> // className is optional; if specified, it is the activity the user chose to uninstall final Intent intent = getIntent(); final Uri packageUri = intent.getData(); if (packageUri == null) { Log.e(TAG, "No package URI in intent"); showAppNotFound(); return; } final String packageName = packageUri.getEncodedSchemeSpecificPart(); if (packageName == null) { Log.e(TAG, "Invalid package name in URI: " + packageUri); showAppNotFound(); return; } final IPackageManager pm = IPackageManager.Stub.asInterface( ServiceManager.getService("package")); mDialogInfo = new DialogInfo(); mDialogInfo.user = intent.getParcelableExtra(Intent.EXTRA_USER); if (mDialogInfo.user == null) { mDialogInfo.user = android.os.Process.myUserHandle(); } mDialogInfo.allUsers = intent.getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, false); mDialogInfo.callback = intent.getIBinderExtra(PackageInstaller.EXTRA_CALLBACK); try { mDialogInfo.appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES, mDialogInfo.user.getIdentifier()); } catch (RemoteException e) { Log.e(TAG, "Unable to get packageName. Package manager is dead?"); } if (mDialogInfo.appInfo == null) { Log.e(TAG, "Invalid packageName: " + packageName); showAppNotFound(); return; } // The class name may have been specified (e.g. when deleting an app from all apps) final String className = packageUri.getFragment(); if (className != null) { try { mDialogInfo.activityInfo = pm.getActivityInfo( new ComponentName(packageName, className), 0, mDialogInfo.user.getIdentifier()); } catch (RemoteException e) { Log.e(TAG, "Unable to get className. Package manager is dead?"); // Continue as the ActivityInfo isn't critical. } } showConfirmationDialog(); } private void showConfirmationDialog() { showDialogFragment(new UninstallAlertDialogFragment()); } private void showAppNotFound() { showDialogFragment(new AppNotFoundDialogFragment()); } private void showDialogFragment(DialogFragment fragment) { FragmentTransaction ft = getFragmentManager().beginTransaction(); Fragment prev = getFragmentManager().findFragmentByTag("dialog"); if (prev != null) { ft.remove(prev); } fragment.show(ft, "dialog"); } void startUninstallProgress() { Intent newIntent = new Intent(Intent.ACTION_VIEW); // newIntent.putExtra(Intent.EXTRA_USER, mDialogInfo.user); // 要求卸载该应用对于用户程序和数据 newIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, mDialogInfo.allUsers); newIntent.putExtra(PackageInstaller.EXTRA_CALLBACK, mDialogInfo.callback); // appInfo封装了卸载程序的信息(ApplicationInfo对象) newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mDialogInfo.appInfo); // 允许卸载窗口返回是否卸载成功的标识 if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); } // 指定卸载应用的activity newIntent.setClass(this, UninstallAppProgress.class); startActivity(newIntent); } void dispatchAborted() { if (mDialogInfo != null && mDialogInfo.callback != null) { final IPackageDeleteObserver2 observer = IPackageDeleteObserver2.Stub.asInterface( mDialogInfo.callback); try { observer.onPackageDeleted(mDialogInfo.appInfo.packageName, PackageManager.DELETE_FAILED_ABORTED, "Cancelled by user"); } catch (RemoteException ignored) { } } } }</span>
<span style="color:#666666">package com.android.packageinstaller;
public class UninstallAppProgress extends Activity implements OnClickListener {
private final String TAG="UninstallAppProgress";
private boolean localLOGV = false;

private ApplicationInfo mAppInfo;
private boolean mAllUsers;
private UserHandle mUser;
private IBinder mCallback;

private TextView mStatusTextView;
private Button mOkButton;
private Button mDeviceManagerButton;
private ProgressBar mProgressBar;
private View mOkPanel;
private volatile int mResultCode = -1;

private static final int UNINSTALL_COMPLETE = 1;

private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UNINSTALL_COMPLETE:    //完成了卸载
mResultCode = msg.arg1;
final String packageName = (String) msg.obj;

if (mCallback != null) {
final IPackageDeleteObserver2 observer = IPackageDeleteObserver2.Stub
                                .asInterface(mCallback);
try {
                            observer.onPackageDeleted(mAppInfo.packageName, mResultCode,
                                    packageName);
                        } catch (RemoteException ignored) {
                        }
                        finish();
return;
                    }
//  返回卸载的状态
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
                        Intent result = new Intent();
                        result.putExtra(Intent.EXTRA_INSTALL_RESULT, mResultCode);
//  根据是否成功卸载返回对应的值
setResult(mResultCode == PackageManager.DELETE_SUCCEEDED
                                ? Activity.RESULT_OK : Activity.RESULT_FIRST_USER,
                                        result);
                        finish();
return;
                    }
// 下面是处理不需要返回卸载状态的情况
                    // Update the status text
final String statusText;
switch (msg.arg1) {
//  成功卸载
case PackageManager.DELETE_SUCCEEDED:
                            statusText = getString(R.string.uninstall_done);
// Show a Toast and finish the activity
Context ctx = getBaseContext();
                            Toast.makeText(ctx, statusText, Toast.LENGTH_LONG).show();
                            setResultAndFinish(mResultCode);
return;
//  由于安全策略的原因导致卸载失败
case PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER:
                            Log.d(TAG, "Uninstall failed because " + packageName
                                    + " is a device admin");
mDeviceManagerButton.setVisibility(View.VISIBLE);
                            statusText = getString(R.string.uninstall_failed_device_policy_manager);
break;
case PackageManager.DELETE_FAILED_OWNER_BLOCKED:
                            UserManager userManager =
                                    (UserManager) getSystemService(Context.USER_SERVICE);
                            IPackageManager packageManager = IPackageManager.Stub.asInterface(
                                    ServiceManager.getService("package"));
                            List<UserInfo> users = userManager.getUsers();
int blockingUserId = UserHandle.USER_NULL;
for (int i = 0; i < users.size(); ++i) {
final UserInfo user = users.get(i);
try {
if (packageManager.getBlockUninstallForUser(packageName,
                                            user.id)) {
                                        blockingUserId = user.id;
break;
                                    }
                                } catch (RemoteException e) {
// Shouldn't happen.
Log.e(TAG, "Failed to talk to package manager", e);
                                }
                            }
mDeviceManagerButton.setVisibility(View.VISIBLE);
if (blockingUserId == UserHandle.USER_OWNER) {
                                statusText = getString(R.string.uninstall_blocked_device_owner);
                            } else if (blockingUserId == UserHandle.USER_NULL) {
                                Log.d(TAG, "Uninstall failed for " + packageName + " with code "
+ msg.arg1 + " no blocking user");
                                statusText = getString(R.string.uninstall_failed);
                            } else {
                                String userName = userManager.getUserInfo(blockingUserId).name;
                                statusText = String.format(
                                        getString(R.string.uninstall_blocked_profile_owner),
                                        userName);
                            }
break;
default:    //其他原因导致卸载失败
Log.d(TAG, "Uninstall failed for " + packageName + " with code "
+ msg.arg1);
                            statusText = getString(R.string.uninstall_failed);
break;
                    }
mStatusTextView.setText(statusText);

// Hide the progress bar; Show the ok button
mProgressBar.setVisibility(View.INVISIBLE);
mOkPanel.setVisibility(View.VISIBLE);
break;
default:
break;
            }
        }
    };

@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
        Intent intent = getIntent();
//  获取ApplicationInfo对象
mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
//  获取是否删除所有用户数据的标识
mAllUsers = intent.getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, false);
if (mAllUsers && UserHandle.myUserId() != UserHandle.USER_OWNER) {
throw new SecurityException("Only owner user can request uninstall for all users");
        }
mUser = intent.getParcelableExtra(Intent.EXTRA_USER);
if (mUser == null) {
mUser = android.os.Process.myUserHandle();
        } else {
            UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
            List<UserHandle> profiles = userManager.getUserProfiles();
if (!profiles.contains(mUser)) {
throw new SecurityException("User " + android.os.Process.myUserHandle() + " can't "
+ "request uninstall for user " + mUser);
            }
        }
mCallback = intent.getIBinderExtra(PackageInstaller.EXTRA_CALLBACK);
        initView(); //  卸载的逻辑
}
//  卸载监听类
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
public void packageDeleted(String packageName, int returnCode) {
            Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE);
            msg.arg1 = returnCode;
            msg.obj = packageName;
mHandler.sendMessage(msg);
        }
    }

void setResultAndFinish(int retCode) {
        setResult(retCode);
        finish();
    }

public void initView() {
//  获取待卸载程序 是否为被更新的系统应用(该标识只作为标题显示用)
boolean isUpdate = ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
        setTitle(isUpdate ? R.string.uninstall_update_title : R.string.uninstall_application_title);
        setContentView(R.layout.uninstall_progress);
// Initialize views
View snippetView = findViewById(R.id.app_snippet);
        PackageUtil.initSnippetForInstalledApp(this, mAppInfo, snippetView);
mStatusTextView = (TextView) findViewById(R.id.center_text);
mStatusTextView.setText(R.string.uninstalling);
mDeviceManagerButton = (Button) findViewById(R.id.device_manager_button);
mDeviceManagerButton.setVisibility(View.GONE);
//  当由于某些安全策略的原因卸载失败,会显示该按钮,点击进入设置activity来改变某些安全策略
mDeviceManagerButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClassName("com.android.settings",
"com.android.settings.Settings$DeviceAdminSettingsActivity");
                intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
                finish();
            }
        });
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mProgressBar.setIndeterminate(true);
// Hide button till progress is being displayed
mOkPanel = (View) findViewById(R.id.ok_panel);
mOkButton = (Button) findViewById(R.id.ok_button);
mOkButton.setOnClickListener(this);
mOkPanel.setVisibility(View.INVISIBLE);
        IPackageManager packageManager =
                IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
//  创建卸载监听
PackageDeleteObserver observer = new PackageDeleteObserver();
try {
//  核心代码,静默卸载
packageManager.deletePackageAsUser(mAppInfo.packageName, observer,
mUser.getIdentifier(),
mAllUsers ? PackageManager.DELETE_ALL_USERS : 0);
        } catch (RemoteException e) {
// Shouldn't happen.
Log.e(TAG, "Failed to talk to package manager", e);
        }
    }

public void onClick(View v) {
if(v == mOkButton) {
            Log.i(TAG, "Finished uninstalling pkg: " + mAppInfo.packageName);
            setResultAndFinish(mResultCode);
        }
    }

@Override
public boolean dispatchKeyEvent(KeyEvent ev) {
if (ev.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (mResultCode == -1) {
// Ignore back key when installation is in progress
return true;
            } else {
// If installation is done, just set the result code
setResult(mResultCode);
            }
        }
return super.dispatchKeyEvent(ev);
    }
}</span>
如果要实现应用程序静默安装和卸载都需要在AndroidManifest文件中添加以下权限(该权限属于系统级别的权限,不能在普通的Android应用中使用)
<users-permission  android:name="android.permission.INSTALL_PACKAGES">
必须对Android应用进行系统签名(platform签名),并且通过刷机或root权限安装到Android系统中


 
 
 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值