今天我们一起看,看看系统是如何在你的手机上安装应用程序的。
入口
单击Apk安装后,将出现以下界面
这是Android Framework提供的软件包安装程序。页面:packageInstallerActivity
package com . Android . package installer;
publicclasspackageinstalleractivityextendsactivity {
公共void onclick (viewv) {
If(v==mOk){
if(){
//.省略一些细节
start install();//开始安装
}
}elseif(v==mCancel){
//Cancelandfinish
}
}
PrivatevoidstartInstall(){
//startsubactivitytoactuallyinstalltheapplication
intent new intent=new intent();
纽因,
MPKGIN);
纽因(MPACKAGEURI);
新的in (this,in);
.//newIn其他参数
start activity(newIntent);
finish();
}
}
在此页面上单击“安装”后,安装包信息将通过internet传递给installing。此activity.installing的作用主要是将包信息发送到PMS,并处理回调。
磷
当然,从onCreate开始。
protectedvoidoncreate(@ nullablebundlesavedinstancestate){
applicationinfoappinfo=getintent()
.getParcelableExtra);
Mpackageuri=getintent()。get data();
.
根据//mPackageURI创建相应的文件
FinalFilesourceFile=newFile();
//显示应用程序信息图标、应用程序名称或程序包名称
Packageu (this,packageu (this,appinfo,
源文件)、r . id . app _ snippet);
//创建并装配传递会话参数的sessionParams
PackageInparams=newPackageIn(
帕克金。MODE _ FULL _ INSTALL);
=package manager . install _ full _ app;
.
=
GetIntent()。getStringExtra);
file file=newFile();
对//APK执行轻量级语法分析,并将语法分析结果分配给与SessionParams相关的字段
Packageparpkg=packagepar(文件,0);
);
);
(请参阅)
PackageHel(pkg、false、);
//在InstallEventReceiver中注册观察者时,将返回新的mInstallId
//InstallEventReceiver是可以通过EventResultPersister接收所有安装事件的BroadcastReceiver
//其中事件将回调到this : launchfinishbasedonresult
min stallid=installeventreceiver
.addObserver(this、Even、
this :3360 launchfinishbasedonresult);
Try{
// PackageInstaller 的 createSession // 方法内部会通过 IPackageInstaller 与 PackageInstallerservice进行进程间通信, // 最终调用的是 PackageInstallerService 的 createSession 方法来创建并返回 mSessionId mSessionId = getPackageManager().getPackageInstaller().createSession(params); } catch (IOException e) { launchFailure, null); } }In
接下来是 onResume, 通过 InstallingAsyncTask 做一些异步工作
protected void onResume() {
();
// This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller();
PackageIn sessionInfo = in(mSessionId);
if (sessionInfo != null && !()) {
mInstallingTask = new InstallingAsyncTask();
mIn();
} else {
// we will receive a broadcast when the install is finished
mCancelBu(false);
setFinishOnTouchOutside(false);
}
}
}
InstallingAsyncTask
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageIn; {
@Override
protected PackageIn doInBackground(Void... params) {
PackageIn session;
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
(0);
File file = new File());
OutputStream out = ("PackageInstaller", 0, sizeBytes)
InputStream in = new FileInputStream(file)
long sizeBytes = ();
byte[] buffer = new byte[1024 * 1024];
while (true) {
int numRead = in.read(buffer);
if (numRead == -1) {
(out);
break;
}
// 将 APK 文件通过 IO 流的形式写入到 PackageIn 中
out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
(fraction);
}
}
return session;
}
@Override
protected void onPostExecute(PackageIn session) {
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadca);
broadca(
getPackageManager().getPermissionControllerPackageName());
broadcastIn, mInstallId);
PendingIntent pendingIntent = PendingIn(
In,
mInstallId,
broadcastIntent,
PendingIn);
// 调用 PackageIn 的 commit 方法,进行安装
());
}
}
来看下 PackageIn 里的实现
public static class Session implements Closeable {
private IPackageInstallerSession mSession;
public void commit(@NonNull IntentSender statusReceiver) {
try {
mSe(statusReceiver, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
mSession 的类型为 IPackageInstallerSession,这说明要通过 IPackageInstallerSession 来进行进程间的通信,最终会调用PackageInstallerSession 的 commit 方法,剧透一下在这个类执行完后,就会进入鼎鼎大名的 PMS 去真正的执行安装了 :
public class PackageInstallerSession extends IPackageIn {
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
// 将包的信息封装为 PackageInstallObserverAdapter
final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
mContext, statusReceiver, sessionId,
isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId);
mRemoteObserver = ada();
// 通过 Handler 处理消息事件
mHandler.obtainMessage(msg_COMMIT).sendToTarget();
}
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch ) {
case MSG_COMMIT:
commitLocked();
break;
}
}
};
private final PackageManagerService mPm;
private void commitLocked() throws PackageManagerException {
mPm.installStage(mPackageName, stageDir, ...);
}
}
mPm 就是系统服务 PackageManagerService。installStage 方法就是正式开始 apk 的安装过程。这个过程包括两大步:拷贝安装包、装载代码
拷贝安装包
继续看 installStage 的代码
// PackageManagerService.java
void installStage(String packageName, File stagedDir,...) {
final Message msg = mHandler.obtainMessage(INIT_COPY);
// 把之前传入的 sessionParams 安装信息,及其它信息封装成 InstallParams
final InstallParams params = new InstallParams(origin, null, observer,
, installerPackageName, ,
verificationInfo, user, ,
, signingDetails, installReason);
mHandler.sendMessage(msg);
}
发送的消息 INIT_COPY 从名字上就知道是去初始化复制
class PackageHandler extends Handler {
void doHandleMessage(Message msg) {
switch ) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) m;
// 调用 connectToService 方法连接安装 apk 的 Service 服务。
if (!connectToService()) {
return;
} else {
// Once we bind to the service, the first
// pending request will be processed.
mPendingIn(idx, params);
}
}
}
}
private boolean connectToService() {
// 通过隐式 Intent 绑定 Service,实际绑定的 Service 是 DefaultContainerService
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
if (service, mDefContainerConn,
Con, U)) {
mBound = true;
return true;
}
return false;
}
}
当绑定 Service 成功之后,会在 mDefContainerConn 的 onServiceConnection 方法中发送一个绑定操作的 Message,如下所示:
class DefaultContainerConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
final IMediaContainerService imcs = IMediaCon
.asInterface(service));
mHandler.sendMessage(MCS_BOUND, imcs));
}
}
// MCS_BOUND 还是在前面的 PackageHandler 处理,直接截取相关代码
{
HandlerParams params = mPendingIn(0);
if ()) {
if () > 0) {
mPendingIn(0);
}
}
}
mPendingInstalls 是一个等待队列,里面保存所有需要安装的 apk 解析出来的 HandlerParams 参数(前面在 INIT_COPY 处理时 add),从 mPendingInstalls 中取出第一个需要安装的 HandlerParams 对象,并调用其 startCopy 方法,在 startCopy 方法中会继续调用一个抽象方法 handleStartCopy 处理安装请求。通过之前的分析,我们知道 HandlerParams 实际类型是 InstallParams 类型,因此最终调用的是 InstallParams 的 handlerStartCopy 方法,这是整个安装包拷贝的核心。
class InstallParams extends HandlerParams {
public void handleStartCopy() throws RemoteException {
if ) {
// 设置安装标志位,决定是安装在手机内部存储空间还是 sdcard 中
if != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
}
}
// 判断安装位置
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
final InstallArgs args = createInstallArgs(this);
// ...
ret = args.copyApk(mContainerService, true);
}
private InstallArgs createInstallArgs(InstallParams params) {
if != null) {
return new MoveInstallArgs(params);
} else {
return new FileInstallArgs(params);
}
}
}
正常的流程下,createInstallArgs 返回的是 FileInstallArgs 对象
FileInstallArgs 的 copyApk 方法
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
return doCopyApk(imcs, temp);
}
private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
// 创建存储安装包的目标路径,实际上是 /data/app/ 应用包名目录
final File tempDir = mIn(volumeUuid, isEphemeral);
final IParcelFileDescriptorFactory target = new IParcelFileDe() {
@Override
public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
final File file = new File(codeFile, name);
final FileDescriptor fd = Os.open(),
O_RDWR | O_CREAT, 0644);
Os.chmod(), 0644);
return new ParcelFileDescriptor(fd);
}
};
// 调用服务的 copyPackage 方法将安装包 apk 拷贝到目标路径中;
ret = imcs.copyPackage.getAbsolutePath(), target);
// 将 apk 中的动态库 .so 文件也拷贝到目标路径中。
ret = Na(handle, libraryRoot,
abiOverride);
}
这里的 IMediaContainerService imcs 就是之前连接上的 DefaultContainerService
DefaultContainerService
copyPackage 方法本质上就是执行 IO 流操作,具体如下:
// new IMediaCon()
public int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {
PackageLite pkg = null;
final File packageFile = new File(packagePath);
pkg = PackagePar(packageFile, 0);
return copyPackageInner(pkg, target);
}
// DefaultContainerService
private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target){
copyFile, target, "ba;);
if (!ArrayU)) {
for (int i = 0; i < ; i++) {
copyFile[i], target, "split_" + [i] + ".apk");
}
}
return PackageManager.INSTALL_SUCCEEDED;
}
private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName){
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(sourcePath);
out = new ParcelFileDe(
(targetName, ParcelFileDe));
FileU(in, out);
} finally {
IoU(out);
IoU(in);
}
}
最终安装包在 data/app 目录下以 ba 的方式保存,至此安装包拷贝工作就已经完成。
装载代码
安装包拷贝完成,就要开始真正安装了。代码回到上述的 HandlerParams 中的 startCopy 方法:
private abstract class HandlerParams {
final boolean startCopy() {
...
handleStartCopy();
handleReturnCode();
}
}
class InstallParams extends HandlerParams {
@Override
void handleReturnCode() {
// If mArgs is null, then MCS couldn't be reached. When it
// reconnects, it will try again to install. At that point, this
// will succeed.
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
}
}
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
mHandler.post(new Runnable() {
public void run() {
PackageInstalledInfo res = new PackageInstalledInfo();
if == PackageManager.INSTALL_SUCCEEDED) {
// 预安装操作,主要是检查安装包的状态,确保安装环境正常,如果安装环境有问题会清理拷贝文件
args.doPreInstall);
synchronized (mInstallLock) {
// 安装阶段
installPackageTracedLI(args, res);
}
args.doPostInstall, res.uid);
}
...
}
}
}
}
installPackageLI
installPackageTracedLI 方法中添加跟踪 Trace,然后调用 installPackageLI 方法进行安装。这个方法有 600 行,取部分关键代码:
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
...
PackageParser pp = new PackageParser();
final PackagePar pkg;
// 1. parsePackage
pkg = (tmpPackageFile, parseFlags);
// 2. 校验安装包签名
final KeySetManagerService ksms = mSe;
if (signatureCheckPs, scanFlags)) {
if (!k(signatureCheckPs, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ + " upgrade keys do not match the "
+ "previously installed version");
return;
}
}
// 3. 设置相关权限,生成、移植权限
int N = ();
for (int i = N-1; i >= 0; i--) {
final PackagePar perm = (i);
...
}
// 4. 生成安装包Abi(Application binary interface,应用二进制接口)
try {
String abiOverride = (TextU) ?
args.abiOverride : );
final boolean extractNativeLibs = !();
derivePackageAbi(pkg, abiOverride, extractNativeLibs);
} catch (PackageManagerException pme) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
return;
}
// 5. 冻结 APK,执行替换安装 或 新安装,
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
"installPackageLI")) {
if (replace) {
replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
installerPackageName, res, args.installReason);
} else {
private void installNewPackageLIF((pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res, args.installReason);
}
}
// 5. 优化dex文件(实际为 dex2oat 操作,用来将 apk 中的 dex 文件转换为 oat 文件)
if (performDexopt) {
mPackageDexO(pkg, ,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault),
dexoptOptions);
}
...
}
最后我们来看一下 installNewPackageLIF
private void installNewPackageLIF(PackagePar pkg, final @ParseFlags int parseFlags,
final @ScanFlags int scanFlags,...) {
// 继续扫描解析 apk 安装包文件,保存 apk 相关信息到 PMS 中,并创建 apk 的 data 目录,具体路径为 /data/data/应用包名
PackagePar newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags,
Sy(), user);
// 更新系统设置中的应用信息,比如应用的权限信息
updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
if == PackageManager.INSTALL_SUCCEEDED) {
// 安装然后准备 APP 数据
prepareAppDataAfterInstallLIF(newPackage);
} else {
// 如果安装失败,则将安装包以及各种缓存文件删除
deletePackageLIF(pkgName, U, false, null,
PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
}
}
prepareAppDataAfterInstallLIF 还会有一系列的调用
prepareAppDataAfterInstallLIF()
-> prepareAppDataLIF()
-> prepareAppDataLeafLIF()
-> mIn(...)
final Installer mInstaller;
private void prepareAppDataLeafLIF(...) {
// 最终调用 系统服务 Installer 安装
ceDataInode = mIn(volumeUuid, packageName, userId, flags,
appId, seInfo, a);
}
public class Installer extends SystemService {
...
}
至此整个 apk 的安装过程结束,实际上安装成功之后,还会发送一个 App 安装成功的广播 ACTION_PACKAGE_ADDED。手机桌面应用注册了这个广播,当接收到应用安装成功之后,就将 apk 的启动 icon 显示在桌面上。
总结
在手机上仅仅是点一下安装按钮而已,背后却有着这么繁琐的流程,相信通过今天的学习大家应该能对系统的应用安装流程有一个完整的认知。回顾一下安装的流程如下:
- 点击 APK 安装,会启动 PackageInstallerActivity,再进入 InstallInstalling 这两个 Activity 显示应用信息
- 点击页面上的安装,将 APK 信息存入 PackageIn 传到 PMS
- PMS会做两件事,拷贝安装包和装载代码
- 在拷贝安装包过程中会开启 Service 来 copyAPK 、检查apk安装路径,包的状态
- 拷贝完成以 ba 形式存在/data/app包名下
- 装载代码过程中,会继续解析 APK,把清单文件内容存放于 PMS
- 对 apk 进行签名校验
- 安装成功后,更新应用设置权限,发送广播通知桌面显示APP图标,安装失败则删除安装包和各种缓存文件
- 执行 dex2oat 优化
「本文源码基于 Android 28」
1.《【v8ms28l01怎么安装软件】谈谈APK安装过程。》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《【v8ms28l01怎么安装软件】谈谈APK安装过程。》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/why/3036878.html