Android应用安装过程分析(一)

手头上只有Android4.3的源代码,凑活着看,过程都大差不差,哪里写的不对的希望看到的大神指出。

Android应用安全有四种方式:

1.通过SD卡里的APK文件安装

2.网络下载应用安装,通过market应用完成,没有安装界面

3.ADB工具安装,没有安装界面。

4.系统应用安装,开机时完成

先看SD卡中APK文件安装

一般通过java代码进行应用安装会创建Intent对象,调用startActivity安装指定APK

Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(Uri.parse("file:/sdcard/xxx.apk"));
startActivity(intent);
之后会进入校验页面 PackageInstallerActivity

源码路径:android/packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener {
    private static final String TAG = "PackageInstaller";
    private Uri mPackageURI;    
    private Uri mOriginatingURI;
    private Uri mReferrerURI;
    private int mOriginatingUid = VerificationParams.NO_UID;
    private ManifestDigest mPkgDigest;

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

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

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

    // 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;
@Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        // get intent information
        final Intent intent = getIntent();
        mPackageURI = intent.getData();<span style="white-space:pre">		</span>//获取应用路径或Package
        mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
        mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
        mPm = getPackageManager();<span style="white-space:pre">		</span>//创建PackageManager对象

        final String scheme = mPackageURI.getScheme();<span style="white-space:pre">					</span>//返回当前协议
        if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {<span style="white-space:pre">	</span>//协议类型判断
            Log.w(TAG, "Unsupported scheme " + scheme);
            setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);<span style="white-space:pre">			</span>//设置返回结果信息
            return;
        }

        final PackageUtil.AppSnippet as;
        if ("package".equals(mPackageURI.getScheme())) {<span style="white-space:pre">						</span>//协议类型为package
            try {
                mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(),
                        PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES);<span style="white-space:pre">	</span>//获取应用信息,如应用名、权限等
            } catch (NameNotFoundException e) {
            }
            if (mPkgInfo == null) {<span style="white-space:pre">		</span>//获取失败处理分支
                Log.w(TAG, "Requested package " + mPackageURI.getScheme()
                        + " not available. Discontinuing installation");
                showDialogInner(DLG_PACKAGE_ERROR);
                setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
                return;
            }
            as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),<span style="white-space:pre">	</span>//AppSnippet对象封装了应用的标题和图标
                    mPm.getApplicationIcon(mPkgInfo.applicationInfo));
        } else {<span style="white-space:pre">										</span>//协议类型为file
            final File sourceFile = new File(mPackageURI.getPath());<span style="white-space:pre">				</span>//根据路径创建文件对象
            PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);<span style="white-space:pre">		</span>//创建文件分析器

            // 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);
                return;
            }
            mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
                    PackageManager.GET_PERMISSIONS, 0, 0, null,
                    new PackageUserState());<span style="white-space:pre">				</span>//获取应用信息
            mPkgDigest = parsed.manifestDigest;
            as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
        }
        
        //set view
        setContentView(R.layout.install_start);<span style="white-space:pre">				</span>//设置画面
        mInstallConfirm = findViewById(R.id.install_confirm_panel);
        mInstallConfirm.setVisibility(View.INVISIBLE);
        PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);

        mOriginatingUid = getOriginatingUid(intent);

        // Deal with install source.
        String callerPackage = getCallingPackage();//<span style="color: rgb(51, 51, 51); font-family: Roboto, sans-serif; font-size: 14px; line-height: 24px;">Return the name of the package that invoked this activity</span>
        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_SYSTEM) != 0) {
                        // System apps don't need to be approved.
                        initiateInstall();
                        return;
                    }
                }
            } catch (NameNotFoundException e) {
            }
        }

        // Check unknown sources.判断是否允许未知来源的应用
        if (!isInstallingUnknownAppsAllowed()) {
            //ask user to enable setting first询问是否要通过设置打开未知来源
            showDialogInner(DLG_UNKNOWN_APPS);
            return;
        }
        initiateInstall();
    }
检查协议,根据不同协议进行处理,最终都会调用initiateInstall

private void initiateInstall() {
        String pkgName = mPkgInfo.packageName;<span style="white-space:pre">						</span>
        // 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;
        }
        startInstallConfirm();//开始安装认证
    }

initiateInstall就是进行检查,是否已存在,检查完毕调用startInstallConfirm

    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);

        boolean permVisible = false;<span style="white-space:pre">	</span>//是否显示权限,true显示,false不显示
        mScrollView = null;
        mOkCanInstall = false;
        int msg = 0;
        if (mPkgInfo != null) {
            AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);<span style="white-space:pre">	</span>//AppSecurityPermissions封装了一些处理权限的<span style="white-space:pre">											</span>//功能
            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 //判断是否为系统应用设置msg,该值用于确定不同的布局文件
                        ? R.string.install_confirm_question_update_system
                        : R.string.install_confirm_question_update;
                mScrollView = new CaffeinatedScrollView(this);<span style="white-space:pre">	</span>//用于显示权限的滚动视图
                mScrollView.setFillViewport(true);
                if (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0) {  //判断应用有新权限
                    permVisible = true;
                    mScrollView.addView(perms.getPermissionsView(<span style="white-space:pre">		</span>//将权限加入滚动视图
                            AppSecurityPermissions.WHICH_NEW));
                } else {<span style="white-space:pre">			</span>//没有需要显示的权限,只显示名称和图标
                    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("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) {<span style="white-space:pre">	</span>//滚动视图显示与隐私相关
                    ((ViewGroup)root.findViewById(R.id.privacylist)).addView(
                            perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL));
                } else {
                    root.findViewById(R.id.privacylist).setVisibility(View.GONE);
                }
                if (ND > 0) {<span style="white-space:pre">	</span>//显示与设备相关
                    ((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("all").setIndicator(
                        getText(R.string.allPerms)), root);
            }
        }
        if (!permVisible) {<span style="white-space:pre">	</span>//没有任何权限
            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);
            findViewById(R.id.filler).setVisibility(View.VISIBLE);
            findViewById(R.id.divider).setVisibility(View.GONE);
            mScrollView = null;
        }
        if (msg != 0) {<span style="white-space:pre">	</span>//选择布局文件
            ((TextView)findViewById(R.id.install_confirm_question)).setText(msg);
        }
        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;
                }
            });
        }
    }
正常情况下,此时单击按钮“安装”,即安装应用

    public void onClick(View v) {
        if(v == mOk) {
            if (mOkCanInstall || mScrollView == null) {<span style="white-space:pre">	</span>//选择“安装”按钮
                // Start subactivity to actually install the application
                Intent newIntent = new Intent();
                newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
                        mPkgInfo.applicationInfo);
                newIntent.setData(mPackageURI);
                newIntent.setClass(this, InstallAppProgress.class);
                newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);
                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);<span style="white-space:pre">	</span>//开始安装界面
                finish();
            } else {<span style="white-space:pre">	</span>//单击“下一步”按钮继续显示权限列表
                mScrollView.pageScroll(View.FOCUS_DOWN);
            }
        } else if(v == mCancel) {
            // Cancel and finish
            setResult(RESULT_CANCELED);
            finish();
        }
    }
}
启动安装界面就会进入InstallAppProgress,与 PackageInstallerActivity在同一个包下

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        Intent intent = getIntent();<span style="white-space:pre">	</span>//没什么好注释的
        mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
        mPackageURI = intent.getData();

        final String scheme = mPackageURI.getScheme();
        if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
            throw new IllegalArgumentException("unexpected scheme " + scheme);
        }

        initView();
    }
    public void initView() {
        setContentView(R.layout.op_progress);
        int installFlags = 0;
        PackageManager pm = getPackageManager();
        try {//如果应用已被安装,设置安装模式为更新
            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;
        if ("package".equals(mPackageURI.getScheme())) {//协议类型为package,则更新程序
            as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo),
                    pm.getApplicationIcon(mAppInfo));
        } else {//为file,则安装
            final File sourceFile = new File(mPackageURI.getPath());
            as = PackageUtil.getAppSnippet(this, mAppInfo, sourceFile);
        }
        mLabel = as.label;
        
<span style="white-space:pre">	</span>...
        ...

        String installerPackageName = getIntent().getStringExtra(
                Intent.EXTRA_INSTALLER_PACKAGE_NAME);
        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 {//更新应用
                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);
        }
    }
initView代码看起来很多,核心也就两句

pm.installExistingPackage(mAppInfo.packageName);
以及

pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
                    installerPackageName, verificationParams, null);
这两个都是静默方法,执行过程中不会有提示

InstallAppProgress中内嵌了一个类,用于提供给用户一个反馈

    class PackageInstallObserver extends IPackageInstallObserver.Stub {
        public void packageInstalled(String packageName, int returnCode) {
            Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
            msg.arg1 = returnCode;
            mHandler.sendMessage(msg);
        }
    }
待续










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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值