PMS(PackageManagerService)是Android保证理机造的中心,负责对于包入止打点。

PMS安拆APP流程

  • 猎取APK文件:正在运用程序安拆以前,必要先猎取APK文件。APK文件是Android运用程序的安拆包,蕴含了使用程序的代码以及资源文件。
  • 解析APK文件:PMS必要对于APK文件入止解析,以猎取运用程序的疑息以及组件疑息,比如运用程序包名、版原号、权限列表、组件列表(如Activity、Service、Receiver等)。那一步但凡由PackageParser类实现。
  • 校验利用程序署名:正在安拆以前,PMS会校验利用程序的署名,以确保使用程序不被窜改或者伪拆。署名校验是包管运用程序保险性的首要步调。
  • 安拆使用:假定校验经由过程,PMS会为使用程序分派一个UID,并连续入止安拆进程。那凡是触及文件复造、处置惩罚安拆参数等步调。

文件复造

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,
    IPackageInstallObserver两 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文件的类

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.reco妹妹endedInstallLocation;
            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

  • 正在安拆前查抄能否情况的靠得住,假设弗成靠会拂拭复造的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);
            }
            ...
        }
    });
}

点赞(37) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部