深入Android系统(十)PMS-3-应用安装过程

本文详细解析了Android应用的安装流程,从Intent启动安装、PackageInstallerService响应、InstallStart活动、PackageInstallerActivity的作用,到文件复制和安装阶段。过程中涉及到的关键类如PackageInstallerSession、InstallParams和InstallArgs,以及安装过程中对Uri、Intent、服务连接和文件操作的处理。此外,还简要提及了安装后的广播通知和观察者回调。

研究应用的安装过程,老样子,我们还是先从使用入手。

Android中,通过发送Intent就可以启动应用的安装过程,比如:

    Uri uri = Uri.fromFile(new File(apkFilePath));
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(uri,"application/vnd.android.package-archive");
    startActivity(intent);

而在Android的系统应用PackageInstaller中有一个InstallStart会响应这个Intent

        <activity android:name=".InstallStart"
            android:theme="@style/Installer"
                android:exported="true"
                android:excludeFromRecents="true">
            <intent-filter android:priority="1">
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.INSTALL_PACKAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="file" />
                <data android:scheme="content" />
                <data android:mimeType="application/vnd.android.package-archive" />
            </intent-filter>
            ......
        </activity>

InstallStart中会进行各种Uri的判断,最终会跳转到一个叫做PackageInstallerActivity的界面。

国内的厂商基本上会在InstallStart这里进行修改,替换为自己的安装界面

对于PackageInstallerActivity来说,它的主要作用是

  • 解析Uri协议进行解析,包括filepackage两种
    • 如果是file协议会解析APK文件得到包信息PackageInfo
  • 对未知来源进行处理
    • 如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源,就会初始化安装确认界面
    • 如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面
  • 提取并在界面展示应用对应的权限

当点击确认安装后,其实会执行到startInstall()方法,相关内容如下:

    private void startInstall() {
   
   
        // Start subactivity to actually install the application
        Intent newIntent = new Intent();
        ......
        newIntent.setData(mPackageURI);
        newIntent.setClass(this, InstallInstalling.class);
        ......
        startActivity(newIntent);
        finish();
    }

上面的逻辑是跳转到InstallInstalling界面进行安装,我们看看这个Activity

@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
   
   
        ......
        if ("package".equals(mPackageURI.getScheme())) {
   
   
            // 直接安装 package
            try {
   
   
                getPackageManager().installExistingPackage(appInfo.packageName);
                launchSuccess();
            } catch (PackageManager.NameNotFoundException e) {
   
   
                launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
            }
        } else {
   
   
            // 对于 file 安装,按照session的逻辑去走
            // 这部分在onResume中开始
            final File sourceFile = new File(mPackageURI.getPath());
            ......
            if (savedInstanceState != null) {
   
   
                mSessionId = savedInstanceState.getInt(SESSION_ID);
                mInstallId = savedInstanceState.getInt(INSTALL_ID);
                ......
            } else {
   
   
                ......
                mSessionId = getPackageManager().getPackageInstaller().createSession(params);
                ......
                // 创建应用安装状态的Observer
                // 真正注册是在后面 Session 的 commitLocked 中
                // InstallEventReceiver 这里是做了二次封装,方便进行持久化操作
                InstallEventReceiver.addObserver(this, mInstallId,
                            this::launchFinishBasedOnResult);
            }
            ......
        }
    }
    @Override
    protected void onResume() {
   
   
        super.onResume();
        // This is the first onResume in a single life of the activity
        if (mInstallingTask == null) {
   
   
            PackageInstaller installer = getPackageManager().getPackageInstaller();
            PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
            // 启动异步安装任务 InstallingAsyncTask 进行一系列的session操作
            if (sessionInfo != null && !sessionInfo.isActive()) {
   
   
                mInstallingTask = new InstallingAsyncTask();
                mInstallingTask.execute();
            }
            ......
        }
    }

从上面的方法我们可以看到安装操作主要分为两个接口:

  • getPackageManager().installExistingPackage():主要是对已经并扫描到SettingsmPackages集合中的应用进行操作
    • 根据当前的userID从集合中查询应用状态,如果存在并且应用没有安装,就进行一些简单的配置工作
    • 最后通过prepareAppDataAfterInstallLIF方法,创建特定userID下的应用数据
  • InstallingAsyncTask任务中的Session系列操作:一个应用完整的安装过程从这里开始
    private final class InstallingAsyncTask extends AsyncTask<Void, Void,
            PackageInstaller.Session> {
         
         
        volatile boolean isDone;
        @Override
        protected PackageInstaller.Session doInBackground(Void... params) {
         
         
            PackageInstaller.Session session;
            ......
            session = getPackageManager().getPackageInstaller().openSession(mSessionId);
            try {
         
         
                File file = new File(mPackageURI.getPath());
                try (InputStream in = new FileInputStream(file)) {
         
         
                    long sizeBytes = file.length();
                    try (OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes)) {
         
         
                        byte[] buffer = new byte[1024 * 1024];
                        while (true) {
         
         
                            .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值