android10 应用安装

**摘要:**本文将详细介绍Android系统中APK的安装流程,从PackageInstallerActivity的bindUi方法到PackageManagerService类的installStage方法,经过权限检查,安装参数设置,APK复制,安装处理,直至最终安装完成。

1. 安装apk的方式:

1.将APK放在手机内存卡手动安装

2.通过ADB安装

3.通过应用商店安装

这三种安装方式到PackageManagerService之后安装流程都是相同的

2. apk的安装过程

/frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

复制代码
private void bindUi() {
    mAlert.setIcon(mAppSnippet.icon);
    mAlert.setTitle(mAppSnippet.label);
    mAlert.setView(R.layout.install_content_view);
    mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
            (ignored, ignored2) -> {
                if (mOk.isEnabled()) {
                    if (mSessionId != -1) {
                        mInstaller.setPermissionsResult(mSessionId, true);
                        finish();
                    } else {
						// 进行APK安装
                        startInstall();
                    }
                }
            }, null);
    mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
            (ignored, ignored2) -> {
                // Cancel and finish
                setResult(RESULT_CANCELED);
                if (mSessionId != -1) {
                    mInstaller.setPermissionsResult(mSessionId, false);
                }
                finish();
            }, null);
    setupAlert();

    mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
    mOk.setEnabled(false);
}

点击一个未安装的apk后,会弹出安装界面,点击确定按钮后会进入PackageInstallerActivity类的bindUi()方法中,点击安装后调用startInstall方法进行安装

复制代码
private void startInstall() {
    // 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, InstallInstalling.class);
    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 != PackageInstaller.SessionParams.UID_UNKNOWN) {
        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();
}

跳转到InstallInstalling类

xref: /frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java

复制代码
protected void onResume() {
    super.onResume();
    if (mInstallingTask == null) {
        PackageInstaller installer = getPackageManager().getPackageInstaller();
        PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

        if (sessionInfo != null && !sessionInfo.isActive()) {
			//创建InstallingAsyncTask
            mInstallingTask = new InstallingAsyncTask();
            mInstallingTask.execute();
        } else {
            // we will receive a broadcast when the install is finished
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        }
    }
}

创建InstallingAsyncTask

复制代码
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
        PackageInstaller.Session> {
    volatile boolean isDone;

    @Override
    protected PackageInstaller.Session doInBackground(Void... params) {
        PackageInstaller.Session session;
        try {
			//获取session
            session = getPackageManager().getPackageInstaller().openSession(mSessionId);
        } catch (IOException e) {
            return null;
        }

        session.setStagingProgress(0);

        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) {
                        int numRead = in.read(buffer);

                        if (numRead == -1) {
                            session.fsync(out);
                            break;
                        }

                        if (isCancelled()) {
                            session.close();
                            break;
                        }
						// 将apk的信息写入session中
                        out.write(buffer, 0, numRead);
                        if (sizeBytes > 0) {
                            float fraction = ((float) numRead / (float) sizeBytes);
                            session.addProgress(fraction);
                        }
                    }
                }
            }

            return session;
        } catch (IOException | SecurityException e) {
            Log.e(LOG_TAG, "Could not write package", e);

            session.close();

            return null;
        } finally {
            synchronized (this) {
                isDone = true;
                notifyAll();
            }
        }
    }

    @Override
    protected void onPostExecute(PackageInstaller.Session session) {
        if (session != null) {
            Intent broadcastIntent = new Intent(BROADCAST_ACTION);
            broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            broadcastIntent.setPackage(getPackageName());
            broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);

            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    InstallInstalling.this,
                    mInstallId,
                    broadcastIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
			// 调用PackageInstaller.Session进行安装
            session.commit(pendingIntent.getIntentSender());
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        } else {
            getPackageManager().getPackageInstaller().abandonSession(mSessionId);

            if (!isCancelled()) {
                launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
            }
        }
    }
}

1.在doInBackground方法中根据apk的路径将apk的信息写入到session中

2.在onPostExecute方法中调用session的commit方法进行安装

xref: /frameworks/base/core/java/android/content/pm/PackageInstaller.java

复制代码
public void commit(@NonNull IntentSender statusReceiver) {
    try {
        mSession.commit(statusReceiver, false);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

mSession的类型为IPackageInstallerSession,最终会调用到PackageInstallerSession的commit方法

xref: /frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java

复制代码
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
    ..................................................
	
    mHandler.obtainMessage(MSG_COMMIT).sendToTarget();	
}

想handler发送了一个类型为MSG_COMMIT的消息,最终会调用commitNonStagedLocked方法

复制代码
private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
        throws PackageManagerException {
		
	...........................................................
	
    if (isMultiPackage()) {
        ...........................................................
		
        if (!success) {
            try {
                mRemoteObserver.onPackageInstalled(
                        null, failure.error, failure.getLocalizedMessage(), null);
            } catch (RemoteException ignored) {
            }
            return;
        }
        mPm.installStage(activeChildSessions);
    } else {
        mPm.installStage(committingSession);
    }
}

调用PackageManagerService的installStage方法

/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

复制代码
void installStage(ActiveInstallSession activeInstallSession) {
    if (DEBUG_INSTANT) {
        if ((activeInstallSession.getSessionParams().installFlags
                & PackageManager.INSTALL_INSTANT_APP) != 0) {
            Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
        }
    }
    final Message msg = mHandler.obtainMessage(INIT_COPY);
	// 创建InstallParams,设置安装包的安装数据
    final InstallParams params = new InstallParams(activeInstallSession);
    params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
    msg.obj = params;

    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
            System.identityHashCode(msg.obj));
    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
            System.identityHashCode(msg.obj));
	
    mHandler.sendMessage(msg);
}

创建InstallParams对象设置安装包的数据,让通过Handler发送INIT_COPY类型的消息

复制代码
private abstract class HandlerParams {
    
	.....................................................................    

    final void startCopy() {
        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
        handleStartCopy();
        handleReturnCode();
    }

    abstract void handleStartCopy();
    abstract void handleReturnCode();
}

事件最终会调用到内部类HandlerParams里面的startCopy方法 , 在startCopy方法里面先后调用了handleStartCopy和handleReturnCode方法。

复制代码
public void handleStartCopy() {
    ...................................................................
	
	// 快速、轻量级地解析一个APK文件,提取其最基本的安装信息,用于后续的安装位置决策和空间检查 
    pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
            origin.resolvedPath, installFlags, packageAbiOverride);

    ...................................................................

    if (!origin.staged && pkgLite.recommendedInstallLocation
            == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
        // TODO: focus freeing disk space on the target device
        final StorageManager storage = StorageManager.from(mContext);
        final long lowThreshold = storage.getStorageLowBytes(
                Environment.getDataDirectory());
		// 计算一个APK(或拆分APK集合)在安装完成后,在设备上实际占用的存储空间大小
        final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
                origin.resolvedPath, packageAbiOverride);
        if (sizeBytes >= 0) {
            try {
                mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
                pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                        origin.resolvedPath, installFlags, packageAbiOverride);
            } catch (InstallerException e) {
                Slog.w(TAG, "Failed to free cache", e);
            }
        }

        ...................................................................
    }


    if (ret == PackageManager.INSTALL_SUCCEEDED) {
        ...................................................................
		
		// 决定应用最终安装位置的核心策略方法
		loc = installLocationPolicy(pkgLite);
		if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
			ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
		} else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
			ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
		} else if (!onInt) {
			// Override install location with flags
			if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
				// Set the flag to install on external media.
				installFlags &= ~PackageManager.INSTALL_INTERNAL;
			} else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
				if (DEBUG_INSTANT) {
					Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
				}
				installFlags |= PackageManager.INSTALL_INSTANT_APP;
				installFlags &= ~PackageManager.INSTALL_INTERNAL;
			} else {
				// Make sure the flag for installing on external
				// media is unset
				installFlags |= PackageManager.INSTALL_INTERNAL;
			}
		}
    }

   ...................................................................

    if (ret == PackageManager.INSTALL_SUCCEEDED) {
        // TODO: http://b/22976637
        // Apps installed for "all" users use the device owner to verify the app
        UserHandle verifierUser = getUser();
        if (verifierUser == UserHandle.ALL) {
            verifierUser = UserHandle.SYSTEM;
        }

        /*
         * Determine if we have any installed package verifiers. If we
         * do, then we'll defer to them to verify the packages.
         */
        final int requiredUid = mRequiredVerifierPackage == null ? -1
                : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
                        verifierUser.getIdentifier());
        final int installerUid =
                verificationInfo == null ? -1 : verificationInfo.installerUid;
        if (!origin.existing && requiredUid != -1
                && isVerificationEnabled(
                        verifierUser.getIdentifier(), installFlags, installerUid)) {
            ...................................................................

            final PackageVerificationState verificationState = new PackageVerificationState(
                    requiredUid, this);

            mPendingVerification.append(verificationId, verificationState);
			// 将APK清单中声明的"可选验证器"与系统中实际存在的验证器进行匹配,并将匹配成功的验证器加入到验证状态管理中。
            final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                    receivers, verificationState);

            DeviceIdleController.LocalService idleController = getDeviceIdleController();
            final long idleDuration = getVerificationTimeout();

            /*
             * If any sufficient verifiers were listed in the package
             * manifest, attempt to ask them.
             */
            if (sufficientVerifiers != null) {
                final int N = sufficientVerifiers.size();
                if (N == 0) {
                    Slog.i(TAG, "Additional verifiers required, but none installed.");
                    ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
                } else {
                    for (int i = 0; i < N; i++) {
                        final ComponentName verifierComponent = sufficientVerifiers.get(i);
                        idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                                verifierComponent.getPackageName(), idleDuration,
                                verifierUser.getIdentifier(), false, "package verifier");
						// 向每个验证器发送广播
                        final Intent sufficientIntent = new Intent(verification);
                        sufficientIntent.setComponent(verifierComponent);
                        mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
                    }
                }
            }

            ........................................................................
        }

        ........................................................................
    }

    mRet = ret;
}

在正式开始复制 APK 文件之前,进行一系列的前置检查、空间确认、安装位置决策以及安全验证的发起工作

复制代码
void handleReturnCode() {
    if (mVerificationCompleted && mEnableRollbackCompleted) {
        if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
            String packageName = "";
            try {
                PackageLite packageInfo =
                        new PackageParser().parsePackageLite(origin.file, 0);
                packageName = packageInfo.packageName;
            } catch (PackageParserException e) {
                Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
            }
            try {
                observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
            } catch (RemoteException e) {
                Slog.i(TAG, "Observer no longer exists.");
            }
            return;
        }
        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
            mRet = mArgs.copyApk();
        }
        processPendingInstall(mArgs, mRet);
    }
}

handleReturnCode方法扮演的就是"守门人"和"执行者"的角色。它的核心职责是等待所有必需的验证(如包验证、完整性验证)完成,一旦条件满足,就正式启动APK文件的拷贝和后续安装流程。

复制代码
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
    if (args.mMultiPackageInstallParams != null) {
        args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
    } else {
		// 将当前的安装状态码封装成一个PackageInstalledInfo对象
        PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
        processInstallRequestsAsync(
                res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                Collections.singletonList(new InstallRequest(args, res)));
    }
}

private void processInstallRequestsAsync(boolean success,
        List<InstallRequest> installRequests) {
    mHandler.post(() -> {
        if (success) {
            for (InstallRequest request : installRequests) {
                request.args.doPreInstall(request.installResult.returnCode);
            }
            synchronized (mInstallLock) {
                installPackagesTracedLI(installRequests);
            }
            for (InstallRequest request : installRequests) {
                request.args.doPostInstall(
                        request.installResult.returnCode, request.installResult.uid);
            }
        }
        for (InstallRequest request : installRequests) {
            restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                    new PostInstallData(request.args, request.installResult, null));
        }
    });
}

installPackagesTracedLI是PMS中执行实际安装逻辑的关键方法。installPackagesTracedLI最终会调用installPackagesLI方法

复制代码
private void installPackagesLI(List<InstallRequest> requests) {
    ....................................................................
	
    boolean success = false;
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
        for (InstallRequest request : requests) {            
            final PrepareResult prepareResult;
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
				// 准备阶段,解析apk的AndroidManifest.xml文件,获取四大组件以及权限信息
                prepareResult = preparePackageLI(request.args, request.installResult);
            } catch (PrepareFailure prepareFailure) {
                request.installResult.setError(prepareFailure.error,
                        prepareFailure.getMessage());
                request.installResult.origPackage = prepareFailure.conflictingPackage;
                request.installResult.origPermission = prepareFailure.conflictingPermission;
                return;
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
			
            ....................................................................
			
            try {
				// 扫描阶段, 确定包名唯一性,校验包有效性,搜集apk信息
                final List<ScanResult> scanResults = scanPackageTracedLI(
                        prepareResult.packageToScan, prepareResult.parseFlags,
                        prepareResult.scanFlags, System.currentTimeMillis(),
                        request.args.user);
                ....................................................................
				
            } catch (PackageManagerException e) {
                request.installResult.setError("Scanning Failed.", e);
                return;
            }
        }
        ....................................................................
		
        synchronized (mPackages) {
            ....................................................................
			
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                commitRequest = new CommitRequest(reconciledPackages,
                        sUserManager.getUserIds());
				// 将应用信息正式写入 PMS 的数据结构中,使应用对系统"可见",唯一可以修改系统状态的地方,必须在此阶段之前确定所有可预测的错误。
                commitPackagesLocked(commitRequest);
                success = true;
            } finally {
                for (PrepareResult result : prepareResults.values()) {
                    if (result.freezer != null) {
                        result.freezer.close();
                    }
                }
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        }
		// 安装后的清理、优化和通知工作
        executePostCommitSteps(commitRequest);
    } finally {
        ..............................................................		
    }
}

1.准备阶段,解析apk的AndroidManifest.xml文件,获取四大组件以及权限信息

2.扫描阶段, 确定包名唯一性,校验包有效性,搜集apk信息

3.将应用信息正式写入 PMS 的数据结构中,使应用对系统"可见",唯一可以修改系统状态的地方,必须在此阶段之前确定所有可预测的错误

4.安装后的清理、优化和通知工作

相关推荐
_MyFavorite_1 小时前
Python 中通过命令行向函数传参
开发语言·chrome·python
墨染天姬1 小时前
【AI】TensorFlow 框架
人工智能·python·tensorflow
yujunl2 小时前
Net Core8项目不能正常发布
开发语言
lly2024062 小时前
JavaScript Window History
开发语言
jianfeng_zhu2 小时前
用java解决空心金字塔的问题
java·开发语言·python
敲代码的嘎仔2 小时前
Java后端开发——Redis面试题汇总
java·开发语言·redis·学习·缓存·面试·职场和发展
天若有情6732 小时前
【原创发布】typechecker:一款轻量级 JS 模板化类型检查工具
开发语言·javascript·npm·ecmascript·类型检查·typechecker
实心儿儿2 小时前
C++ —— 继承
开发语言·c++
佛系豪豪吖2 小时前
OpenClaw(龙虾)彻底卸载教程|Windows+Mac通用,3步无残留
开发语言