美文网首页手机移动程序开发程序员
Android app安装过程分析(基于Nougat)

Android app安装过程分析(基于Nougat)

作者: super_shanks | 来源:发表于2017-02-14 17:06 被阅读3409次

    首先我们要清楚总体可以分成如下几种安装的情况

    • 系统开机的应用安装,安装的是系统级别的应用,用户在没有获取到root权限的情况下无法卸载的应用
    • adb安装的应用,没有安装界面
    • 第三方市场下载的应用,此处要分情况,部分是通过电脑的客户端安装的没有安装的界面,部分是手机上的市场安装的,会有安装的界面

    那么我们就对几种情况一一分析它的安装流程

    开机安装

    1. 首先在开机的时候systemServer会启动PackageMangerService来

      具体是通过systemServer的main()->init1()->init2()->new ServerThread()->构建PMS

      以上都是SystemServer.cpp中的代码,了解即可。我们前往PMS查看接下去的逻辑:在PMS的构造方法中我们看到了一大坨的逻辑
      ,源码过于长,我们直接在构造方法里面搜索如下这两个方法:

    scanDirTracedLI   //最后还是会调用下面的方法,只是对下面的方法做一下跟踪
    scanDirLI
    

    就是通过这两个方法进行应用的安装,从scanDirLI开始追踪:

    private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
            final File[] files = dir.listFiles();
            ...
            for (File file : files) {
                final boolean isPackage = (isApkFile(file) || file.isDirectory())
                        && !PackageInstallerService.isStageName(file.getName());
                if (!isPackage) {
                    // Ignore entries which are not packages
                    continue;
                }
                try {
                    scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                            scanFlags, currentTime, null);
                } catch (PackageManagerException e) {
                    Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
    
                    // Delete invalid userdata apps
                    if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                            e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                        logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
                        removeCodePathLI(file);
                    }
                }
            }
        }
    

    继续看scanPackageTracedLI方法:

    private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
                long currentTime, UserHandle user) throws PackageManagerException {
            if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
            PackageParser pp = new PackageParser();
            pp.setSeparateProcesses(mSeparateProcesses);
            pp.setOnlyCoreApps(mOnlyCore);
            pp.setDisplayMetrics(mMetrics);
    
            if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
                parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
            }
    
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
            final PackageParser.Package pkg;
            try {
                pkg = pp.parsePackage(scanFile, parseFlags);
            } catch (PackageParserException e) {
                throw PackageManagerException.from(e);
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
    
            return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
        }
    

    我们看到从这个方法开始parsePackage, 通过PackageParser解析apk文件,我们可以去到PackageParser的文件中看到这个parsePackage方法就是把安装包中的配置文件解析出来,并且保存到Package中返回出来,中间辗转反侧对于配置文件各种分情况进行parse,最最主要的是parseBaseApkCommon方法,这个方法对manifast文件的标签进行解析,而其中还调用了parseBaseApplication方法对application标签进行解析。

    然后再scanPackageLI->scanPackageDirtyLI,在后者的方法中,我们会把之前解析出来的

    PackageParser.Provider p = pkg.providers.get(i);
                    p.info.processName = fixProcessName(pkg.applicationInfo.processName,
                            p.info.processName, pkg.applicationInfo.uid);
                    mProviders.addProvider(p);
    
    PackageParser.Service s = pkg.services.get(i);
                    s.info.processName = fixProcessName(pkg.applicationInfo.processName,
                            s.info.processName, pkg.applicationInfo.uid);
                    mServices.addService(s);
    

    等等,我们会把相应的provider,service,receiver,activity全都保存到PMS的成员集合类中去.

    至此系统应用的安装算是全部完成了,也许你会说我们并有看到什么install的什么方法,其实最最精髓的就是上面最后那一坨1000+行的方法,这里面把所有parser出来的信息全部保存到PMS中去了,而这就是所谓的安装,安装就是一个吧apk中的信息解析出来保存给PMS的过程,然后在launcher上生成一个图标,以供用户打开,仅此而已。


    从网络上下载应用安装

    最终都是通过如下的方式去进行安装的

    String fileName = "/mnt/usb/sda4/test.apk";
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.fromFile(new File(fileName)), "application/vnd.android.package-archive");
    startActivity(intent);
    

    启动的就是PackageInstallerActivity,而这个activity是Android的系统应用之一,源码在package/app/packageinstaller中,具体源码可以前往下面链接查看:
    https://github.com/android/platform_packages_apps_packageinstaller/blob/master/src/com/android/packageinstaller/PackageInstallerActivity.java
    我们在其onCreate方法中看到之后会调用checkIfAllowedAndInitiateInstall->initiateInstall-> startInstallConfirm,会处理有关权限的一些问题

    之后如果我们点击下方的ok按钮,会进入到安装流程:

     public void onClick(View v) {
            if (v == mOk) {
                if (mOkCanInstall || mScrollView == null) {
                    if (mSessionId != -1) {
                        mInstaller.setPermissionsResult(mSessionId, true);
                        clearCachedApkIfNeededAndFinish();
                    } else {
                        startInstall();
                    }
                } else {
                    mScrollView.pageScroll(View.FOCUS_DOWN);
                }
            } else if (v == mCancel) {
               ...
        }
    

    我们接着去startInstall方法看:

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

    跳到InstallAppProgress这个activity,很明显就是我们点击安装之后进入的安装界面,有个进度条一直在闪的那个正在安装的界面。
    onCreate()->initView():

    void initView() {
            setContentView(R.layout.op_progress);
    
            ...
    
            if ("package".equals(mPackageURI.getScheme())) {
                try {
                    pm.installExistingPackage(mAppInfo.packageName);
                    onPackageInstalled(PackageInstaller.STATUS_SUCCESS);
                } catch (PackageManager.NameNotFoundException e) {
                    onPackageInstalled(PackageInstaller.STATUS_FAILURE_INVALID);
                }
            } else {
               ...
    
                mInstallHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        doPackageStage(pm, params);
                    }
                });
            }
        }
    

    精简了一下,主要是这两个方法。

    installExistingPackage

    一个是pm.installExistingPackage,我们知道实际上调用的就是ApplicationPackageManager的installExistingPackage

    
        @Override
        public int installExistingPackage(String packageName) throws NameNotFoundException {
            return installExistingPackageAsUser(packageName, mContext.getUserId());
        }
    
        @Override
        public int installExistingPackageAsUser(String packageName, int userId)
                throws NameNotFoundException {
            try {
                int res = mPM.installExistingPackageAsUser(packageName, userId);
                if (res == INSTALL_FAILED_INVALID_URI) {
                    throw new NameNotFoundException("Package " + packageName + " doesn't exist");
                }
                return res;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    继续,我们前往PMS的installExistingPackageAsUser方法,具体方法不贴出,实际的意思就是这个安装包已经装过了,只是当前用户下还没有安装,就会对后台的设置做一下处理,实际并不涉及到安装的东西的。我们来看另外一个方法

    doPackageStage

    private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) {
            final PackageInstaller packageInstaller = pm.getPackageInstaller();
            PackageInstaller.Session session = null;
            try {
                session = packageInstaller.openSession(sessionId);
                ...
                session.commit(pendingIntent.getIntentSender());
            } catch (IOException e) {
                onPackageInstalled(PackageInstaller.STATUS_FAILURE);
            } finally {
                IoUtils.closeQuietly(session);
            }
        }
    

    当中对session做了很多操作,我们只看最主要的最后一个session.commit,

    • PackageInstaller.Session
      这个session是在5.0之后新加进来的一种安装处理的方式,我们可以把它理解为一种记录,就和浏览器中的session的作用是一样的,它用来保存应用安装的所有信息,当我们的手机如果因为异常只安装了一半退出了之后,当我们下回再次打开手机的时候,可以继续上次的安装。

    ok,我们接着进到PackageInstaller.java看session的commit方法

    public void commit(@NonNull IntentSender statusReceiver) {
                try {
                    mSession.commit(statusReceiver);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
    

    这里的mSession我们看到是

            private IPackageInstallerSession mSession;
    
     /** {@hide} */
            public Session(IPackageInstallerSession session) {
                mSession = session;
            }
    

    万恶的binder,回到上面看session的定义:

    session = packageInstaller.openSession(sessionId);
    

    找openSession方法

    public @NonNull Session openSession(int sessionId) throws IOException {
            try {
                return new Session(mInstaller.openSession(sessionId));
            } catch (RuntimeException e) {
                ExceptionUtils.maybeUnwrapIOException(e);
                throw e;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    mInstaller是什么,

        private final IPackageInstaller mInstaller;
    

    又来一个binder,我们就不继续一步一步贴了,相信读者也可以自己找到最终的实现是在PackageInstallerSession

    @Override
        public void commit(IntentSender statusReceiver) {
            ...
            final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
                    statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
            mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
        }
    

    省去部分直接看到最后给handler发了条消息

            mHandler = new Handler(looper, mHandlerCallback);
    
    private final Handler.Callback mHandlerCallback = new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                // Cache package manager data without the lock held
                final PackageInfo pkgInfo = mPm.getPackageInfo(
                        params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId);
                final ApplicationInfo appInfo = mPm.getApplicationInfo(
                        params.appPackageName, 0, userId);
    
                synchronized (mLock) {
                    if (msg.obj != null) {
                        mRemoteObserver = (IPackageInstallObserver2) msg.obj;
                    }
    
                    try {
                        commitLocked(pkgInfo, appInfo);
                    } catch (PackageManagerException e) {
                        final String completeMsg = ExceptionUtils.getCompleteMessage(e);
                        Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
                        destroyInternal();
                        dispatchSessionFinished(e.error, completeMsg, null);
                    }
    
                    return true;
                }
            }
        };
    

    重要的就是那句commitLocked,这个方法比较长,依然是做一些权限和配置方面的事情,能在方法的最后看到

    mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
                    installerPackageName, installerUid, user, mCertificates);
    

    我们去到PMS的installStage方法:

    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 InstallParams params = new InstallParams(origin, null, observer,
                    sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
                    verificationInfo, user, sessionParams.abiOverride,
                    sessionParams.grantedRuntimePermissions, certificates);
            ...
            msg.obj = params;
            ...
            mHandler.sendMessage(msg);
        }
    

    我们把整个过程精简到上面三局代码,发送一个what为INIT_COPY的消息

    case INIT_COPY: {
                        HandlerParams params = (HandlerParams) msg.obj;
                        int idx = mPendingInstalls.size();
                        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
                        // 此处为了连接服务,初始情况都为false,待服务脸上之后就会把mBound设置为true,就可以进入下面条件
                        // 因此这里我们直接进入else的条件
                        if (!mBound) {
                            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                    System.identityHashCode(mHandler));
                            // If this is the only one pending we might
                            // have to bind to the service again.
                            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;
                            } else {
                                // Once we bind to the service, the first
                                // pending request will be processed.
                                mPendingInstalls.add(idx, params);
                            }
                        } else {
                            mPendingInstalls.add(idx, params);
                            // Already bound to the service. Just make
                            // sure we trigger off processing the first request.
                            if (idx == 0) {
                                mHandler.sendEmptyMessage(MCS_BOUND);
                            }
                        }
                        break;
                    }
    

    直接在最后看到发送了MCS_BOUND消息

     case MCS_BOUND: {
                        ...
                        //服务已经连上,直接跳到else if
                        if (mContainerService == null) {
                            ...
                        } 
                        //等待安装的队列肯定大于0
                        else if (mPendingInstalls.size() > 0) {
                            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");
                                //开始进入到copy
                                if (params.startCopy()) {
                                    // We are done...  look for more work or to
                                    // go idle.
                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
                                            "Checking for more work or unbind...");
                                    // Delete pending install
                                    if (mPendingInstalls.size() > 0) {
                                        mPendingInstalls.remove(0);
                                    }
                                    //如果已经把要安装的都处理完了,那么久断开服务连接
                                    //否则就再发送一个MCS_BOUND信息,继续循环处理
                                    if (mPendingInstalls.size() == 0) {
                                        if (mBound) {
                                            if (DEBUG_SD_INSTALL) Log.i(TAG,
                                                    "Posting delayed MCS_UNBIND");
                                            removeMessages(MCS_UNBIND);
                                            Message ubmsg = obtainMessage(MCS_UNBIND);
                                            // Unbind after a little delay, to avoid
                                            // continual thrashing.
                                            sendMessageDelayed(ubmsg, 10000);
                                        }
                                    } else {
                                        // There are more pending requests in queue.
                                        // Just post MCS_BOUND message to trigger processing
                                        // of next pending install.
                                        if (DEBUG_SD_INSTALL) Log.i(TAG,
                                                "Posting MCS_BOUND for next work");
                                        mHandler.sendEmptyMessage(MCS_BOUND);
                                    }
                                }
                                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                            }
                        } else {
                            // Should never happen ideally.
                            Slog.w(TAG, "Empty queue");
                        }
                        break;
                    }
    

    我们直接进入到startCopy

    final boolean startCopy() {
                boolean res;
                try {
                    if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
                    //尝试的次数超过了最大尝试次数,就宣告失败
                    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();
                        res = true;
                    }
                } catch (RemoteException e) {
                    if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
                    mHandler.sendEmptyMessage(MCS_RECONNECT);
                    res = false;
                }
                //处理return code
                handleReturnCode();
                return res;
            }
    

    我们先来看一下handleStartCopy方法,发现时抽象方法,具体的实现,我们网上可以找到是 InstallParams。

    public void handleStartCopy() throws RemoteException {
        int ret = PackageManager.INSTALL_SUCCEEDED;
        // 决定是安装在手机内还是sdcard中,设置对应标志位
        if (origin.staged) {
            if (origin.file != null) {
                installFlags |= PackageManager.INSTALL_INTERNAL;
                installFlags &= ~PackageManager.INSTALL_EXTERNAL;
            } else if (origin.cid != null) {
                installFlags |= PackageManager.INSTALL_EXTERNAL;
                installFlags &= ~PackageManager.INSTALL_INTERNAL;
            } else {
                throw new IllegalStateException("Invalid stage location");
            }
        }
        ...
        // 检查APK的安装位置是否正确
        if (onInt && onSd) {
            // Check if both bits are set.
            Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
            ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
        } else if (onSd && ephemeral) {
            Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
            ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
        } else {
            ...
        }
        ...
        // createInstallArgs用于创建一个安装参数对象
        final InstallArgs args = createInstallArgs(this);
        
        if (ret == PackageManager.INSTALL_SUCCEEDED) {
            ...
                // 调用InstallArgs的copyApk函数
                ret = args.copyApk(mContainerService, true);
            }
        }
        mRet = ret;
    }
    

    主要工作就是复制apk消息到指定位置
    再来看handleReturnCode

    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);
        }
    }
    

    我们一路看,processPendingInstall()->installPackageTracedLI()->installPackageLI(),整个方法比较长,主要做了清单文件解析和获取证书,提取签名的工作,你可以从这个方法中找到如下代码段,就是这段代码处理了安装

    
        try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
                "installPackageLI")) {
            if (replace) {
                // 4.更新已经存在的packages
                replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                        installerPackageName, res);
            } else {
                // 5.安装新的packages
                installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                        args.user, installerPackageName, volumeUuid, res);
            }
        }
    

    我们继续

    /*
         * Install a non-existing package.
         */
        private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
                int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
                PackageInstalledInfo res) {
            ...
            try {
                PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
                        System.currentTimeMillis(), user);
    
                updateSettingsLI(newPackage, installerPackageName, null, res, user);
    
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                    prepareAppDataAfterInstallLIF(newPackage);
    
                } else {
                    // Remove package from internal structures, but keep around any
                    // data that might have already existed
                    deletePackageLIF(pkgName, UserHandle.ALL, false, null,
                            PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
                }
            } catch (PackageManagerException e) {
                res.setError("Package couldn't be installed in " + pkg.codePath, e);
            }
            ...
        }
    

    经过删减省略,我们看到了我们熟悉的方法scanPackageTracedLI,再具体的步骤见上面系统应用安装。


    最后我们再来看一下另外一种ADB的安装

    adb安装

    当我们在在命令行窗口输入adb install的时候实际上,系统会帮我们运行如下的程序

    db_commandline
        install_app_legacy or install_app 
            pm_command
                send_shell_command
                    Pm.runInstall()
    

    这个过程会把apk文件copy到data/local/tmp/目录下,然后向shell服务发送pm命令安装apk,最后调用Pm.runInstall()方法来安装apk。
    我们可以看到这个方法:

    private int runInstall() throws RemoteException {
            ...
            final int sessionId = doCreateSession(params.sessionParams,
                    params.installerPackageName, params.userId);
    
            try {
                if (inPath == null && params.sessionParams.sizeBytes == 0) {
                    System.err.println("Error: must either specify a package size or an APK file");
                    return 1;
                }
                if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
                        false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
                    return 1;
                }
                if (doCommitSession(sessionId, false /*logSuccess*/)
                        != PackageInstaller.STATUS_SUCCESS) {
                    return 1;
                }
                System.out.println("Success");
                return 0;
            } finally {
                try {
                    mInstaller.abandonSession(sessionId);
                } catch (Exception ignore) {
                }
            }
        }
    

    我们依然省略着看,把上面这一段略去,直接在最下面看到三个重要的方法,doCreateSession,doWriteSession,doCommitSession,直接点开最后一个

    private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
            PackageInstaller.Session session = null;
            try {
                session = new PackageInstaller.Session(
                        mInstaller.openSession(sessionId));
    
                final LocalIntentReceiver receiver = new LocalIntentReceiver();
                session.commit(receiver.getIntentSender());
    
                final Intent result = receiver.getResult();
                final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                        PackageInstaller.STATUS_FAILURE);
                if (status == PackageInstaller.STATUS_SUCCESS) {
                    if (logSuccess) {
                        System.out.println("Success");
                    }
                } else {
                    System.err.println("Failure ["
                            + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
                }
                return status;
            } finally {
                IoUtils.closeQuietly(session);
            }
        }
    

    看到熟悉的session.commit了么,


    总结

    下面是有安装界面的app安装流程,中途插入adb install以及没有安装界面的系统安装。

    • PackageInstallerActivity的onCreate();
    • 根据从Intent中获取的Data的scheme的不同,调用不同的处理逻辑安装App;
    • 解析App文件到Package对象;
    • initInstall()函数获取apk中的权限信息;
    • onClick()监听用户点击同意安装按钮;
    • 启动InstallAppProcess Activity;
    • onCrete()函数调用
    • initView()函数;
    • 继续调用doPackageStage()函数,做session.commit();
      此处插入adb install 1.Pm.runInstall() 2.Pm.doCommitSession()
    • 通过Handler机制启动了startCopy()函数;
    • startCopy()调用了启动了handlerStartCopy()将apk拷贝到/data/app、pkg-name/和把.so文件拷贝到/data/app/pkg-name/lib/的
    • handlerReturnCode()函数;
    • handlerReturnCode调用了installPackageLI()函数;
    • 在installPackageLI()中,首先调用了collectCertificates()函数对apk的签名做了校验,确保apk没有被非法修改(修改其中的文件);
      接着,调用collectManifestDigest()函数计算了Manifest.xml的文件摘要,并且存在了Package的manifestDigest成员下;
      接着,将从apk文件中提提取的manifest计算摘要和之前installer解析到的进行比较,若不匹配,则抛出异常。
      然后,对App升级或者使用了共享属性sharedUid的情况校验待安装的App的证书是否匹配,并就升级方式做了具体处理,这里有两个问题,就是升级过程中的Upgrade keysets升级方式和Signature[]的获得不明朗。
    • 根据是升级App还是安装新App,调用不同的函数进行处理环节。
      此处插入系统应用安装 1.scanPackageTracedLI 2.scanPackageLI 3.scanPackageDirtyLI
    • 最后在scanPackageDirtyLI方法中,把所有的provider,service,receiver,activity从parser中拿出来保存到PMS中。

    以上!

    相关文章

      网友评论

        本文标题:Android app安装过程分析(基于Nougat)

        本文链接:https://www.haomeiwen.com/subject/ceuaittx.html