4

PMS安装APP流程解析

 1 month ago
source link: https://www.51cto.com/article/784905.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

PMS安装APP流程解析

作者:Reathin 2024-03-28 18:17:49
PMS(PackageManagerService)是 Android 包管理机制的核心,负责对包进行管理。

PMS(PackageManagerService)是Android包管理机制的核心,负责对包进行管理。

PMS安装APP流程

866e8374737d64b3feb8273a21cc22b5efc572.webp
  • 获取APK文件:在应用程序安装之前,需要先获取APK文件。APK文件是Android应用程序的安装包,包含了应用程序的代码和资源文件。
  • 解析APK文件:PMS需要对APK文件进行解析,以获取应用程序的信息和组件信息,例如应用程序包名、版本号、权限列表、组件列表(如Activity、Service、Receiver等)。这一步通常由PackageParser类完成。
  • 校验应用程序签名:在安装之前,PMS会校验应用程序的签名,以确保应用程序没有被篡改或伪装。签名校验是保证应用程序安全性的重要步骤。
  • 安装应用:如果校验通过,PMS会为应用程序分配一个UID,并继续进行安装过程。这通常涉及文件复制、处理安装参数等步骤。
c80f0622771ba63a88e0536797da2e3b0b790c.webp

PackageManagerService.java#installStage安装阶段:

  • 创建了一个InstallParams对象
  • 创建并发送了一个INIT_COPY的Message消息。
  • InstallParams继承自HandlerParams,用来记录安装应用的参数。

InstallParams中有一个成员变量mArgs,是一个抽象类型InstallArgs,主要是用来执行APK的复制,真正的实现类包括FileInstallArgs用来完成非ASEC应用的安装,ASEC全称是Android Secure External Cache,MoveInstallArgs用来完成已安装应用的移动安装。

void installStage(String packageName, File stagedDir, String stagedCid,
    IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
    String installerPackageName, int installerUid, UserHandle user,
    Certificate[][] certificates) {
    ...
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    final int installReason = fixUpInstallReason(installerPackageName, installerUid,
        sessionParams.installReason);
    final InstallParams params = new InstallParams(origin, null, observer,
        sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
        verificationInfo, user, sessionParams.abiOverride,
        sessionParams.grantedRuntimePermissions, certificates, installReason);
    params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
    msg.obj = params;
    ...
    //发送信息拷贝INIT_COPY 信息
    mHandler.sendMessage(msg);
}

PackageManagerService.java#PackageHandler包处理:connectToService()用于检查和复制可移动文件的服务发送MCS_BOUND信息,触发处理第一个安装请求。

void doHandleMessage(Message msg) {
    switch (msg.what) {
        case INIT_COPY: 
            HandlerParams params = (HandlerParams) msg.obj;
            int idx = mPendingInstalls.size();
            if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
            //mBound用于标识是否绑定了服务,默认值为false
            if (!mBound) { 
                Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS", System.identityHashCode(mHandler));
                //connectToService里面的DefaultContainerService是用于检查和复制可移动文件的服务
                if (!connectToService()) {  
                    Slog.e(TAG, "Failed to bind to media container service");
                    params.serviceError();
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS", System.identityHashCode(mHandler));
                    if (params.traceMethod != null) {
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod, params.traceCookie);
                    }
                    //绑定服务失败则return
                    return;
                } else { 
                    //绑定服务成功,将请求添加到ArrayList类型的mPendingInstalls中,等待处理
                    mPendingInstalls.add(idx, params);
                }
            } else {  
                //已经绑定服务
                mPendingInstalls.add(idx, params);
                if (idx == 0) {   //5
                    //发送MCS_BOUND类型的消息,触发处理第一个安装请求
                    mHandler.sendEmptyMessage(MCS_BOUND);
                }
            }
            break;
        ....
    }
}

MCS_BOUND 流程处理:

case MCS_BOUND: 
    if (mContainerService == null) {         //判断是否已经绑定了服务
        if (!mBound) {            //绑定服务的标识位,没有绑定成功
            Slog.e(TAG, "Cannot bind to media container service");
            for (HandlerParams params : mPendingInstalls) {
                params.serviceError();
                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(params));
                if (params.traceMethod != null) {
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod, params.traceCookie);
                }
                return;
            }   
            //绑定失败,清空安装请求队列
            mPendingInstalls.clear();
        } else {             // 绑定成功
            //继续等待绑定服务
            Slog.w(TAG, "Waiting to connect to media container service");
        }
    } else if (mPendingInstalls.size() > 0) {        //安装APK的队列
        HandlerParams params = mPendingInstalls.get(0);   //安装队列有参数
        if (params != null) {
            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(params));
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
            if (params.startCopy()) {               //HandlerParams开始拷贝
                if (DEBUG_SD_INSTALL) Log.i(TAG, "Checking for more work or unbind...");
                    //如果APK安装成功,删除本次安装请求
                    if (mPendingInstalls.size() > 0) {
                        mPendingInstalls.remove(0);
                    }
                    if (mPendingInstalls.size() == 0) {  //安装队列没有参数
                        if (mBound) {            //已经绑定服务,需要发送一个解绑MCS_UNBIND的message
                            //如果没有安装请求了,发送解绑服务的请求
                            if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting delayed MCS_UNBIND");
                                removeMessages(MCS_UNBIND);
                                Message ubmsg = obtainMessage(MCS_UNBIND);
                                sendMessageDelayed(ubmsg, 10000);
                            }
                        } else {
                            if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting MCS_BOUND for next work");
                                //如果还有其他的安装请求,接着发送MCS_BOUND消息继续处理剩余的安装请求       
                                mHandler.sendEmptyMessage(MCS_BOUND);
                            }
                        }
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }else {
                        Slog.w(TAG, "Empty queue");
                    }
            break;

DefaultContainerService: 真正处理复制APP文件的类

096e2b746edf7a4398b638e65cb0faf2ac5a70.webp

PackageManagerService.java#HandlerParams#startCopy开始复制:

  • 尝试安装次数是否超过4次,超过就移除安装的列表数据
  • handleStartCopy : //复制APK文件
  • handleReturnCode : //开始安装APK
final boolean startCopy() {
    boolean res;
    try {
        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
        //startCopy方法尝试的次数,超过了4次,就放弃这个安装请求
        if (++mRetries > MAX_RETRIES) {
            Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
            mHandler.sendEmptyMessage(MCS_GIVE_UP);  //发送放弃安装信息
            handleServiceError();
            return false;
        } else {
            handleStartCopy();      //复制APK文件
            res = true;
        }
    } catch (RemoteException e) {
        if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
            mHandler.sendEmptyMessage(MCS_RECONNECT);
            res = false;
        }
        handleReturnCode();   //处理复制APK后的安装APK逻辑
        return res;
    }
}

PackageManagerService.java#InstallParams#handleStartCopy复制apk文件:

  • 获取APP的部分安装信息
  • 获取APP的安装位置
  • InstallArgs复制APP----> FileInstallArgs复制APP---->DefaultContainerService复制APP

InstallArgs做为抽象类,FileInstallArgs和MoveInstallArgs继承InstallArgs FileInstallArgs对data/data/包名(系统应用),MoveInstallArgs用于处理已安装APK的移动:

public void handleStartCopy() throws RemoteException {
    ...
    //确定APK的安装位置。onSd:安装到SD卡, onInt:内部存储即Data分区,ephemeral:安装到临时存储(Instant Apps安装)            
    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;
    PackageInfoLite pkgLite = null;
    if (onInt && onSd) {
        // APK不能同时安装在SD卡和Data分区
        Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
        ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
        //安装标志冲突,Instant Apps不能安装到SD卡中
    } else if (onSd && ephemeral) {
        Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
        ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
    } else {
        //获取APK的少量的信息
        pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, packageAbiOverride);
        if (DEBUG_EPHEMERAL && ephemeral) {
            Slog.v(TAG, "pkgLite for install: " + pkgLite);
        }
        ...
        if (ret == PackageManager.INSTALL_SUCCEEDED) {
            //判断安装的位置
            int loc = pkgLite.recommendedInstallLocation;
            if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
               ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
               ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
            } 
            ...
        }else {
            loc = installLocationPolicy(pkgLite);     //确定APP安装的位置
             ...
        }
    }
    //根据InstallParams创建InstallArgs对象
    final InstallArgs args = createInstallArgs(this);    InstallArgs作用时:复制和重命名APK
    mArgs = args;
    if (ret == PackageManager.INSTALL_SUCCEEDED) {
        ...
        if (!origin.existing && requiredUid != -1 && isVerificationEnabled(verifierUser.getIdentifier(), installFlags, installerUid)) {
           ...
        } else{
            ret = args.copyApk(mContainerService, true);     // InstallArgs开始复制APP
        }
    }
    mRet = ret;
}

private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
    ...
    try {
        final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
        //创建临时文件存储目录
        final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
        codeFile = tempDir;
        resourceFile = tempDir;
    } catch (IOException e) {
        Slog.w(TAG, "Failed to create copy file: " + e);
        return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    }
    ...
    int ret = PackageManager.INSTALL_SUCCEEDED;
    ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
    ...
    return ret;
}

安装APK

83bf0ef8527661e6c5f982c90aee97392d951c.webp
  • 在安装前检查是否环境的可靠,如果不可靠会清除复制的APK文件。
  • installPackageTracedLI其内部会调用PMS的installPackageLI方法,进行APP安装。
  • 处理安装后操作,如果安装不成功,删除掉安装相关的目录与文件。
final boolean startCopy() {
    ......
    handleStartCopy();  //APP文件复制拷贝
    .....
    //开始安装APP
    handleReturnCode();
}
   
void handleReturnCode() {
    ........
    if (mArgs != null) {
        processPendingInstall(mArgs, mRet);
    }
}

private void processPendingInstall(final InstallArgs args, final int currentStatus) {
    mHandler.post(new Runnable() {
        public void run() {
            mHandler.removeCallbacks(this);
            PackageInstalledInfo res = new PackageInstalledInfo();
            res.setReturnCode(currentStatus);
            res.uid = -1;
            res.pkg = null;
            res.removedInfo = null;
            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                //安装前处理
                args.doPreInstall(res.returnCode);
                synchronized (mInstallLock) {
                    //开始安装
                    installPackageTracedLI(args, res);
                }
                //安装后收尾
                args.doPostInstall(res.returnCode, res.uid);
            }
            ...
        }
    });
}
责任编辑:赵宁宁 来源: 沐雨花飞蝶

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK