Android_PackageInstall源码分析&静默安装

来源:互联网 发布:芜湖 网络推广专员 编辑:程序博客网 时间:2024/05/19 03:30

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);
应用程序安装源码:
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 applicationsprivate ApplicationInfo mAppInfo = null;private InstallFlowAnalytics mInstallFlowAnalytics;// View for install progressView mInstallConfirm;// Buttons to indicate user acceptanceprivate 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 showDialogprivate 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() {@Overridepublic 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() {@Overridepublic 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 againremoveDialog(id);        showDialog(id);    }@Overridepublic 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 appCharSequence 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 applicationsIntent 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 appCharSequence 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 activityIntent 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 pkgtry {// 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);    }@Overrideprotected 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 viewsetContentView(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 applicationint 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 insteadint 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 doreturn 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 itif (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;    }@Overridepublic void onBackPressed() {if (mSessionId != -1) {mInstaller.setPermissionsResult(mSessionId, false);        }mInstallFlowAnalytics.setFlowFinished(                InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);super.onBackPressed();    }// Generic handling when pressing back keypublic 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);//  设置要安装的URInewIntent.setData(mPackageURI);//  指定安装activitynewIntent.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 finishsetResult(RESULT_CANCELED);if (mSessionId != -1) {mInstaller.setPermissionsResult(mSessionId, false);            }mInstallFlowAnalytics.setFlowFinished(                    InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);            finish();        }    }}
startInstallConfirm方法主要是通过getPermissionsView方法获取不同权限的View,并在滚动视图中显示这些view
AppSecurityPermissions.WHICH_NEW    新加入的权限
AppSecurityPermissions.WHICH_PERSONAL    与用户隐私相关的权限
AppSecurityPermissions.WHICH_DEVICE    与设备相关的权限
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 textmProgressBar.setVisibility(View.INVISIBLE);// Show the ok buttonint 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 buttonmLaunchIntent = 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;        }    }@Overridepublic void onCreate(Bundle icicle) {super.onCreate(icicle);        Intent intent = getIntent();//  获取待安装应用相关的值mAppInfo和mPackageURImAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);mInstallFlowAnalytics = intent.getParcelableExtra(EXTRA_INSTALL_FLOW_ANALYTICS);mInstallFlowAnalytics.setContext(this);mPackageURI = intent.getData();//  验证scheme是否为file或packagefinal 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();    }@Overridepublic 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 applicationsIntent 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更新UIMessage 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对象,否则返回nullPackageInfo 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 displayedmOkPanel = (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 nameString installerPackageName = getIntent().getStringExtra(                Intent.EXTRA_INSTALLER_PACKAGE_NAME);//  对于普通的Android应用没下吗连个uri为nullUri 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);        }    }@Overrideprotected 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();    }}
PackageManager的installExistingPackage和installPackageWithVerificationAndEncryption都是静默安装,安装过程不会出现任何提示,不过这两个方法被设为hide,不能在普通Android应用中调用
查看源码发现安装过程中弹出的校验窗口是PackageInstaller有意展示的,同时Android的静默安装时通过如上方法实现的
应用程序卸载源码:
package com.android.packageinstaller;public class UninstallerActivity extends Activity {private static final String TAG = "UninstallerActivity";public static class UninstallAlertDialogFragment extends DialogFragment implementsDialogInterface.OnClickListener {@Overridepublic 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();        }@Overridepublic void onClick(DialogInterface dialog, int which) {if (which == Dialog.BUTTON_POSITIVE) {//  开始卸载应用((UninstallerActivity) getActivity()).startUninstallProgress();            } else {    //  取消((UninstallerActivity) getActivity()).dispatchAborted();            }        }@Overridepublic void onDismiss(DialogInterface dialog) {super.onDismiss(dialog);            getActivity().finish();        }    }public static class AppNotFoundDialogFragment extends DialogFragment {@Overridepublic 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();        }@Overridepublic 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;@Overridepublic 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 uninstallfinal 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);        }//  指定卸载应用的activitynewIntent.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) {            }        }    }}
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 textfinal String statusText;switch (msg.arg1) {//  成功卸载case PackageManager.DELETE_SUCCEEDED:                            statusText = getString(R.string.uninstall_done);// Show a Toast and finish the activityContext 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 buttonmProgressBar.setVisibility(View.INVISIBLE);mOkPanel.setVisibility(View.VISIBLE);break;default:break;            }        }    };@Overridepublic 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 viewsView 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() {@Overridepublic 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 displayedmOkPanel = (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);        }    }@Overridepublic boolean dispatchKeyEvent(KeyEvent ev) {if (ev.getKeyCode() == KeyEvent.KEYCODE_BACK) {if (mResultCode == -1) {// Ignore back key when installation is in progressreturn true;            } else {// If installation is done, just set the result codesetResult(mResultCode);            }        }return super.dispatchKeyEvent(ev);    }}
如果要实现应用程序静默安装和卸载都需要在AndroidManifest文件中添加以下权限(该权限属于系统级别的权限,不能在普通的Android应用中使用)
<users-permission  android:name="android.permission.INSTALL_PACKAGES">
必须对Android应用进行系统签名(platform签名),并且通过刷机或root权限安装到Android系统中




2 0