Android APK安裝流程(3)--Copy舊代碼兼容

  • 第7步 開啟真正的安裝之路

在開啟繼上文中的分析之前掠抬,我來大體做個簡單總結說明:
Android10的安裝流程變化了不少蒸走,同樣為了兼容之前的流程,導致代碼里有很多不合理或者說重復判斷的情況出現(xiàn)带族,甚至還有前后矛盾的地方∠沽欤總體上Android 10 安裝應用要考慮的因素比較多,有以下幾個方面:

  • 1.系統(tǒng)應用只允許安裝到/data分區(qū)随夸。
  • 2.分區(qū)空間要足夠九默。
  • 3.覆蓋安裝要保持和原有安裝在同一個分區(qū)。
  • 4.是否允許第三方應用安裝到/data分區(qū)宾毒。
  • 5.是否強制允許安裝應用到外置存儲驼修。
  • 6.AndroidManifest.xml里面的installLocation 標簽。auto, internalOnly乙各,preferExternal

前面5點在上文的分析中基本上都有體現(xiàn)墨礁,也比較容易理解。這里我們著重說以下第6點耳峦,AndroidManifest恩静。在Android10中,默認的installLocation是internalOnly蹲坷, 也就是只允許應用安裝到/data分區(qū)驶乾,但是需要考慮之前是否已經(jīng)安裝過這個應用,如果已經(jīng)在其他分區(qū)安裝過循签,則可能發(fā)生不兼容级乐,auto 和 preferExternal都是參考值,目前Android已經(jīng)不在允許將應用直接安裝到主存儲县匠,只允許將應用安裝到內(nèi)置存儲和內(nèi)置擴展存儲风科。這是基于安全考慮,另外其實目前的主存儲也是從內(nèi)置存儲或者擴展的內(nèi)置存儲上使用fuse劃分出來的一個目錄聚唐,二者其實是共用存儲空間的丐重,所以安裝到主存儲上其實意義不大,所以preferExternal標簽其實已經(jīng)被架空杆查。

說到代碼架空,本文中分析的不少代碼是為了兼容老流程為存在的臀蛛,所以也有不少代碼本來是被架空的亲桦,也就是很多邏輯其實是走不到的。

OK浊仆,我們繼續(xù)客峭!

上文我們說到在InstallInstalling的onResume()方法中主要對各種文件執(zhí)行整理認證,剔除不必要的文件和邏輯抡柿,執(zhí)行到最后mHandler.obtainMessage(MSG_COMMIT).sendToTarget()

這個mHandler是PackgeInstallerSession的屬性舔琅,封裝了下面的mHandlerCallback作為callback處理,可以接收MSG_COMMIT和MSG_ON_PACKAGE_INSTALLED事件:

    private final Handler.Callback mHandlerCallback = new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_COMMIT:
                    handleCommit();//***1***
                    break;
                case MSG_ON_PACKAGE_INSTALLED:
                    final SomeArgs args = (SomeArgs) msg.obj;
                    final String packageName = (String) args.arg1;
                    final String message = (String) args.arg2;
                    final Bundle extras = (Bundle) args.arg3;
                    final IPackageInstallObserver2 observer = (IPackageInstallObserver2) args.arg4;
                    final int returnCode = args.argi1;
                    args.recycle();

                    try {
                        observer.onPackageInstalled(packageName, returnCode, message, extras);
                    } catch (RemoteException ignored) {
                    }

                    break;
            }

            return true;
        }
    };

    ···
    mHandler = new Handler(looper, mHandlerCallback);
    ···
    private void handleCommit() {
        if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
            DevicePolicyEventLogger
                    .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
                    .setAdmin(mInstallerPackageName)
                    .write();
        }
        if (params.isStaged) {
            mStagingManager.commitSession(this);
            destroyInternal();
            dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
            return;
        }

        if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
            destroyInternal();
            dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                    "APEX packages can only be installed using staged sessions.", null);
            return;
        }

        // For a multiPackage session, read the child sessions
        // outside of the lock, because reading the child
        // sessions with the lock held could lead to deadlock
        // (b/123391593).
        List<PackageInstallerSession> childSessions = getChildSessions();

        try {
            synchronized (mLock) {
                commitNonStagedLocked(childSessions);//***2***
            }
        } catch (PackageManagerException e) {
            final String completeMsg = ExceptionUtils.getCompleteMessage(e);
            Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
            destroyInternal();
            dispatchSessionFinished(e.error, completeMsg, null);
        }
    }
    @GuardedBy("mLock")
    private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
            throws PackageManagerException {
        final PackageManagerService.ActiveInstallSession committingSession =
                makeSessionActiveLocked();//***3***
        if (committingSession == null) {
            return;
        }
        if (isMultiPackage()) {
            List<PackageManagerService.ActiveInstallSession> activeChildSessions =
                    new ArrayList<>(childSessions.size());
            boolean success = true;
            PackageManagerException failure = null;
            for (int i = 0; i < childSessions.size(); ++i) {
                final PackageInstallerSession session = childSessions.get(i);
                try {
                    final PackageManagerService.ActiveInstallSession activeSession =
                            session.makeSessionActiveLocked();//***4***
                    if (activeSession != null) {
                        activeChildSessions.add(activeSession);
                    }
                } catch (PackageManagerException e) {
                    failure = e;
                    success = false;
                }
            }
            if (!success) {
                try {
                    mRemoteObserver.onPackageInstalled(
                            null, failure.error, failure.getLocalizedMessage(), null);
                } catch (RemoteException ignored) {
                }
                return;
            }
            mPm.installStage(activeChildSessions);//***5***
        } else {
            mPm.installStage(committingSession);//***6***
        }
    }

     /**
     * Stages this session for install and returns a
     * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
     * in case permissions need to be requested before install can proceed.
     */
    @GuardedBy("mLock")
    private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
            throws PackageManagerException {
        if (mRelinquished) {
            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                    "Session relinquished");
        }
        if (mDestroyed) {
            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
        }
        if (!mSealed) {
            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
        }

        //這里的IPackageInstallObserver2在下午有初始化洲劣,是傳遞給PackageManagerService用的备蚓。
        //這個localObserver主要用PackageManagerService的PackageHandler接收處理POST_INSTALL事件時所用
        //注意和上文Android APK安裝流程(2)的mRemoteObserver的區(qū)別
        final IPackageInstallObserver2 localObserver;
        if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
            localObserver = null;
        } else {
            if (!params.isMultiPackage) {
                Preconditions.checkNotNull(mPackageName);
                Preconditions.checkNotNull(mSigningDetails);
                Preconditions.checkNotNull(mResolvedBaseFile);

                if (needToAskForPermissionsLocked()) {//***7***
                    // User needs to confirm installation;
                    // give installer an intent they can use to involve
                    // user.
                    final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
                    intent.setPackage(mPm.getPackageInstallerPackageName());
                    intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
                    try {
                        mRemoteObserver.onUserActionRequired(intent);
                    } catch (RemoteException ignored) {
                    }

                    // Commit was keeping session marked as active until now; release
                    // that extra refcount so session appears idle.
                    closeInternal(false);
                    return null;
                }

                // Inherit any packages and native libraries from existing install that
                // haven't been overridden.
                if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
                    try {
                        final List<File> fromFiles = mResolvedInheritedFiles;
                        final File toDir = resolveStageDirLocked();//***8***

                        if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
                        if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
                            throw new IllegalStateException("mInheritedFilesBase == null");
                        }

                        if (isLinkPossible(fromFiles, toDir)) {
                            if (!mResolvedInstructionSets.isEmpty()) {
                                final File oatDir = new File(toDir, "oat");
                                createOatDirs(mResolvedInstructionSets, oatDir);//***9***
                            }
                            // pre-create lib dirs for linking if necessary
                            if (!mResolvedNativeLibPaths.isEmpty()) {
                                for (String libPath : mResolvedNativeLibPaths) {
                                    // "/lib/arm64" -> ["lib", "arm64"]
                                    final int splitIndex = libPath.lastIndexOf('/');
                                    if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
                                        Slog.e(TAG,
                                                "Skipping native library creation for linking due"
                                                        + " to invalid path: " + libPath);
                                        continue;
                                    }
                                    final String libDirPath = libPath.substring(1, splitIndex);
                                    final File libDir = new File(toDir, libDirPath);
                                    if (!libDir.exists()) {
                                        NativeLibraryHelper.createNativeLibrarySubdir(libDir);//***10***
                                    }
                                    final String archDirPath = libPath.substring(splitIndex + 1);
                                    NativeLibraryHelper.createNativeLibrarySubdir(
                                            new File(libDir, archDirPath));//***11***
                                }
                            }
                            linkFiles(fromFiles, toDir, mInheritedFilesBase);
                        } else {
                            // TODO: this should delegate to DCS so the system process
                            // avoids holding open FDs into containers.
                            copyFiles(fromFiles, toDir);//***12***
                        }
                    } catch (IOException e) {
                        throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                                "Failed to inherit existing install", e);
                    }
                }

                // TODO: surface more granular state from dexopt
                mInternalProgress = 0.5f;
                computeProgressLocked(true);//***13***

                // Unpack native libraries
                extractNativeLibraries(mResolvedStageDir, params.abiOverride,
                        mayInheritNativeLibs());//***14***
            }

            // We've reached point of no return; call into PMS to install the stage.
            // Regardless of success or failure we always destroy session.
            localObserver = new IPackageInstallObserver2.Stub() {
                @Override
                public void onUserActionRequired(Intent intent) {
                    throw new IllegalStateException();
                }

                @Override
                public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                        Bundle extras) {
                    destroyInternal();
                    dispatchSessionFinished(returnCode, msg, extras);
                }
            };
        }

        final UserHandle user;
        if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
            user = UserHandle.ALL;
        } else {
            user = new UserHandle(userId);
        }

        mRelinquished = true;
        return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
                localObserver, params, mInstallerPackageName, mInstallerUid, user,
                mSigningDetails);
    }

makeSessionActiveLocked()方法里主要干了以下4個事兒:

  • 1.如果是SessionParams.MODE_INHERIT_EXISTING安裝模式,那么說明是進行安裝覆蓋囱稽,則會遍歷該目錄下所有的文件郊尝。通過isLinkPossible來檢查安裝原有的文件和當前的原有的文件,mResolvedInheritedFiles中的文件是否可以進行覆蓋战惊,如果文件信息一致說明可以覆蓋流昏,不能則直接拷貝到/data/app/vmdlsessionId.tmp/目錄下。
  • 2.mInternalProgress 設置為0.5,并且更新進度條回調給正在監(jiān)聽的Activity
  • 3.執(zhí)行extractNativeLibraries()方法况凉,創(chuàng)建/data/app/vmdlsessionId.tmp/lib谚鄙,copyNativeBinariesWithOverride并在這個文件下創(chuàng)建該系統(tǒng)支持的一系列的如64位,32位的arm-v7的so庫保存目錄
  • 4.把localObserver這個本地Binder作為參數(shù)調用PMS的installStage方法刁绒,此時安裝步驟將會轉移到PMS中闷营。之后等到PMS到達了某個階段就會回調到onPackageInstalled,從而得知PMS那邊安裝完成了膛锭。

makeSessionActiveLocked()執(zhí)行完畢后可以獲取到committingSession變量粮坞,最后通過mPm.installStage(committingSession);然后進入到PackageManagerService的installStage()方法:

    #PackageManagerService

    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);//***15***
        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);//發(fā)送INIT_COPY事件
    }

mHandler是PackageManagerService的內(nèi)部類PackageHandler:

    class PackageHandler extends Handler {

        PackageHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {
            try {
                doHandleMessage(msg);
            } finally {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            }
        }

        void doHandleMessage(Message msg) {
            switch (msg.what) {
                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    if (params != null) {
                        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                System.identityHashCode(params));
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                        params.startCopy();//***16***
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                    break;
                }
  
      ...

HandlerParams的startCopy()方法:

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

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

代碼走到這里我們發(fā)現(xiàn)2個abstract方法,所以我們需要研究HandlerParams這個類初狰。HandlerParams是個抽象類莫杈,其有2個實現(xiàn)類InstallParams和MultiPackageInstallParams,MutilPackageInstallParams用于負責批量安裝奢入, InstallParams則負責單一安裝筝闹, MutilPackageInstallParams的成員變量mChildParams指向多個InstallParams, 說明批量安裝其實就是調用多個單一安裝的實現(xiàn)的腥光。從上文傳遞的屬性我們可以看到執(zhí)行的是單一安裝也就是InstallParams关顷,所以執(zhí)行的是InstallParams的handleStartCopy()handleReturnCode()

我們來看看InstallParams的handleStartCopy()方法:

         /*
         * Invoke remote method to get package information and install
         * location values. Override install location based on default
         * policy if needed and then create install arguments based
         * on the install location.
         */
        public void handleStartCopy() {
            int ret = PackageManager.INSTALL_SUCCEEDED;

            // If we're already staged, we've firmly committed to an install location
            //1.表示前邊已經(jīng)確定好了安裝目錄(\${stageDir}/PackageInstaller),確定文件是否存在武福,設置INSTALL_INTERNAL標志(double check)议双。
            if (origin.staged) {
                if (origin.file != null) {
                    installFlags |= PackageManager.INSTALL_INTERNAL;
                } else {
                    throw new IllegalStateException("Invalid stage location");
                }
            }

            final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
            final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
            PackageInfoLite pkgLite = null;
            
            // 2 簡單的解析下安裝包的AndroidManifest.xml文件,這里面會調用PackageHelper.resolveInstallLocation()函數(shù)確定推薦的安裝位置捉片。
            pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                    origin.resolvedPath, installFlags, packageAbiOverride);//***19***

            if (DEBUG_INSTANT && ephemeral) {
                Slog.v(TAG, "pkgLite for install: " + pkgLite);
            }

            /*
             * If we have too little free space, try to free cache
             * before giving up.
             */
            // 3. 空間不足使用mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);釋放一些空間平痰,
            //注意3這種情況并沒有使用PackageInstallerSession將安裝文件拷貝到臨時目錄,如果已經(jīng)拷貝伍纫,則并不需要關心空間問題
            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());
              
                final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
                        origin.resolvedPath, packageAbiOverride);//***20***
                if (sizeBytes >= 0) {
                    try {
                        mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);//***21***
                        pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                                origin.resolvedPath, installFlags, packageAbiOverride);//***22***
                    } catch (InstallerException e) {
                        Slog.w(TAG, "Failed to free cache", e);
                    }
                }

                /*
                 * The cache free must have deleted the file we downloaded to install.
                 *
                 * TODO: fix the "freeCache" call to not delete the file we care about.
                 */
                // 3.1 freeCache把安裝包刪了,設置PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE表示是由于空間問題安裝失敗的宗雇。
                if (pkgLite.recommendedInstallLocation
                        == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                    pkgLite.recommendedInstallLocation
                            = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
                }
            }
  
            
            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                // 4.1 錯誤情況處理
                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 if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_APK;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                    ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
                } else {
                    // Override with defaults if needed.
                    // 4.2 前面都處理成功了,看下是否還需要更換安裝位置
                    loc = installLocationPolicy(pkgLite);//***23***
                    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;
                        }
                    }
                }
            }

            final InstallArgs args = createInstallArgs(this);//***24***
            mVerificationCompleted = true;
            mEnableRollbackCompleted = true;
            mArgs = args;

            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());//***25***
                final int installerUid =
                        verificationInfo == null ? -1 : verificationInfo.installerUid;
                if (!origin.existing && requiredUid != -1
                        && isVerificationEnabled(
                                verifierUser.getIdentifier(), installFlags, installerUid)) {//***26***
                    final Intent verification = new Intent(
                            Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
                    verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                    verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                            PACKAGE_MIME_TYPE);
                    verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                    // Query all live verifiers based on current user state
                    final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
                            PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
                            false /*allowDynamicSplits*/);

                    if (DEBUG_VERIFY) {
                        Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
                                + verification.toString() + " with " + pkgLite.verifiers.length
                                + " optional verifiers");
                    }

                    final int verificationId = mPendingVerificationToken++;

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
                            installerPackageName);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
                            installFlags);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
                            pkgLite.packageName);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
                            pkgLite.versionCode);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
                            pkgLite.getLongVersionCode());

                    if (verificationInfo != null) {
                        if (verificationInfo.originatingUri != null) {
                            verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
                                    verificationInfo.originatingUri);
                        }
                        if (verificationInfo.referrer != null) {
                            verification.putExtra(Intent.EXTRA_REFERRER,
                                    verificationInfo.referrer);
                        }
                        if (verificationInfo.originatingUid >= 0) {
                            verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
                                    verificationInfo.originatingUid);
                        }
                        if (verificationInfo.installerUid >= 0) {
                            verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
                                    verificationInfo.installerUid);
                        }
                    }

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

                    mPendingVerification.append(verificationId, verificationState);

                    final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                            receivers, verificationState);//***27***

                    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);//***28***
                            }
                        }
                    }

                    final ComponentName requiredVerifierComponent = matchComponentForVerifier(
                            mRequiredVerifierPackage, receivers);
                    if (ret == PackageManager.INSTALL_SUCCEEDED
                            && mRequiredVerifierPackage != null) {
                        Trace.asyncTraceBegin(
                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
                        /*
                         * Send the intent to the required verification agent,
                         * but only start the verification timeout after the
                         * target BroadcastReceivers have run.
                         */
                        verification.setComponent(requiredVerifierComponent);
                        idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                                mRequiredVerifierPackage, idleDuration,
                                verifierUser.getIdentifier(), false, "package verifier");
                        //***29***
                        mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
                                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
                                new BroadcastReceiver() {
                                    @Override
                                    public void onReceive(Context context, Intent intent) {
                                        final Message msg = mHandler
                                                .obtainMessage(CHECK_PENDING_VERIFICATION);
                                        msg.arg1 = verificationId;
                                        mHandler.sendMessageDelayed(msg, getVerificationTimeout());
                                    }
                                }, null, 0, null, null);

                        /*
                         * We don't want the copy to proceed until verification
                         * succeeds.
                         */
                        mVerificationCompleted = false;
                    }
                }

                if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                    // TODO(ruhler) b/112431924: Don't do this in case of 'move'?
                    final int enableRollbackToken = mPendingEnableRollbackToken++;
                    Trace.asyncTraceBegin(
                            TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
                    mPendingEnableRollback.append(enableRollbackToken, this);

                    final int[] installedUsers;
                    synchronized (mPackages) {
                        PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
                        if (ps != null) {
                            installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
                                    true);
                        } else {
                            installedUsers = new int[0];
                        }
                    }

                    Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
                    enableRollbackIntent.putExtra(
                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
                            enableRollbackToken);
                    enableRollbackIntent.putExtra(
                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
                            installFlags);
                    enableRollbackIntent.putExtra(
                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
                            installedUsers);
                    enableRollbackIntent.putExtra(
                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
                            getRollbackUser().getIdentifier());
                    enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                            PACKAGE_MIME_TYPE);
                    enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                    // Allow the broadcast to be sent before boot complete.
                    // This is needed when committing the apk part of a staged
                    // session in early boot. The rollback manager registers
                    // its receiver early enough during the boot process that
                    // it will not miss the broadcast.
                    enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                     //***30***
                    mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
                            android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
                            new BroadcastReceiver() {
                                @Override
                                public void onReceive(Context context, Intent intent) {
                                    // the duration to wait for rollback to be enabled, in millis
                                    long rollbackTimeout = DeviceConfig.getLong(
                                            DeviceConfig.NAMESPACE_ROLLBACK,
                                            PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
                                            DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
                                    if (rollbackTimeout < 0) {
                                        rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
                                    }
                                    final Message msg = mHandler.obtainMessage(
                                            ENABLE_ROLLBACK_TIMEOUT);
                                    msg.arg1 = enableRollbackToken;
                                    mHandler.sendMessageDelayed(msg, rollbackTimeout);
                                }
                            }, null, 0, null, null);

                    mEnableRollbackCompleted = false;
                }
            }

            mRet = ret;
        }
  • 1.調用PackageManagerServiceUtils.getMinimalPackageInfo()掃描安裝apk信息到Android系統(tǒng)中莹规,并對存儲空間是否足夠進行判斷赔蒲,如果不夠則進行內(nèi)存釋放。其實這個方法里執(zhí)行的基本上都是無用代碼良漱,因為在之前我們因為分析到通過Session已經(jīng)完成計算存儲空間舞虱,釋放內(nèi)存等的操作。
    /**
     * Parse given package and return minimal details.
     */
    public static PackageInfoLite getMinimalPackageInfo(Context context, String packagePath,
            int flags, String abiOverride) {
        final PackageInfoLite ret = new PackageInfoLite();
        if (packagePath == null) {
            Slog.i(TAG, "Invalid package file " + packagePath);
            ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
            return ret;
        }

        final File packageFile = new File(packagePath);
        final PackageParser.PackageLite pkg;
        final long sizeBytes;
        try {
            //對apk包進行解析,就是解析包中的AndroidManifest最外層的數(shù)據(jù).
            //拿到版本號债热,包名砾嫉,包的路徑等等不包含四大組件的基礎信息。
            //和parseMonolithicPackageLite作用十分相似窒篱,核心還是遍歷這個目錄里面                
            //所有的apk文件焕刮,以splitName為key舶沿,ApkLite為value保存起來,
            //并且找出null為key對應的baseApk的value
            pkg = PackageParser.parsePackageLite(packageFile, 0);//***31***
            // 對安裝后的包進行大小統(tǒng)計配并,計算結果是:
            // 安裝后大小 = 每一個包安裝路徑下文件的大小(/data/app/vmdlsessionId.tmp/base.apk)+ .dm后綴的文件大小 + so庫大小
            sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);//***32***
        } catch (PackageParserException | IOException e) {
            Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);

            if (!packageFile.exists()) {
                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
            } else {
                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
            }

            return ret;
        }
        //計算出返回的結果
        final int recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
                pkg.packageName, pkg.installLocation, sizeBytes, flags);//***33***

        ret.packageName = pkg.packageName;
        ret.splitNames = pkg.splitNames;
        ret.versionCode = pkg.versionCode;
        ret.versionCodeMajor = pkg.versionCodeMajor;
        ret.baseRevisionCode = pkg.baseRevisionCode;
        ret.splitRevisionCodes = pkg.splitRevisionCodes;
        ret.installLocation = pkg.installLocation;
        ret.verifiers = pkg.verifiers;
        ret.recommendedInstallLocation = recommendedInstallLocation;
        ret.multiArch = pkg.multiArch;

        return ret;
    }
  • 2.通過createInstallArgs()構建InstallArgs對象(這里是FileInstallArgs)括荡,如果getMinimalPackageInfo()的安裝成功了,則會進行判斷該包是否已經(jīng)安裝過且isVerificationEnabled()是否允許進行包校驗器進行校驗溉旋。
    private InstallArgs createInstallArgs(InstallParams params) {
        if (params.move != null) {
            return new MoveInstallArgs(params);//***34***
        } else {
            return new FileInstallArgs(params);//***35***
        }
    }
  • 3.如果可以進行包校驗,則通過data為"application/vnd.android.package-archive"調用queryIntentReceiversInternal()方法查找有沒有注冊在Android系統(tǒng)中的包校驗廣播接受者畸冲;通過matchVerifiers()方法篩選出當前合適的包校驗器;最后依次發(fā)送廣播观腊,讓包校驗接受者根據(jù)包名邑闲,versionCode,packageName梧油,安裝來源等信息進行校驗.
  • 4.調用mContext.sendOrderedBroadcastAsUser()發(fā)送廣播苫耸,驗證完畢后,調用final Message msg = mHandler.obtainMessage(CHECK_PENDING_VERIFICATION);給mHandler發(fā)消息:
                ···
                case CHECK_PENDING_VERIFICATION: {
                    final int verificationId = msg.arg1;
                    final PackageVerificationState state = mPendingVerification.get(verificationId);

                    if ((state != null) && !state.timeoutExtended()) {
                        final InstallParams params = state.getInstallParams();
                        final InstallArgs args = params.mArgs;
                        final Uri originUri = Uri.fromFile(args.origin.resolvedFile);

                        Slog.i(TAG, "Verification timed out for " + originUri);
                        mPendingVerification.remove(verificationId);

                        final UserHandle user = args.getUser();
                        if (getDefaultVerificationResponse(user)
                                == PackageManager.VERIFICATION_ALLOW) {
                            Slog.i(TAG, "Continuing with installation of " + originUri);
                            state.setVerifierResponse(Binder.getCallingUid(),
                                    PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
                            broadcastPackageVerified(verificationId, originUri,
                                    PackageManager.VERIFICATION_ALLOW, user);
                        } else {
                            broadcastPackageVerified(verificationId, originUri,
                                    PackageManager.VERIFICATION_REJECT, user);
                            params.setReturnCode(
                                    PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
                        }

                        Trace.asyncTraceEnd(
                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
                        params.handleVerificationFinished();//***36***
                    }
                    break;
                }
                ···

params.handleVerificationFinished()方法:

        void handleVerificationFinished() {
            mVerificationCompleted = true;//在handleReturnCode()里用到
            handleReturnCode();
        }
  • 5.同4相似儡陨,調用mContext.sendOrderedBroadcastAsUser()發(fā)送廣播褪子,對Rollback(這個Rollback是什么?)進行驗證骗村。然后調用final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);給mHandler發(fā)消息:
                ···
                case ENABLE_ROLLBACK_TIMEOUT: {
                    final int enableRollbackToken = msg.arg1;
                    final InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
                    if (params != null) {
                        final InstallArgs args = params.mArgs;
                        final Uri originUri = Uri.fromFile(args.origin.resolvedFile);

                        Slog.w(TAG, "Enable rollback timed out for " + originUri);
                        mPendingEnableRollback.remove(enableRollbackToken);

                        Slog.w(TAG, "Continuing with installation of " + originUri);
                        Trace.asyncTraceEnd(
                                TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
                        params.handleRollbackEnabled();//***37***
                        Intent rollbackTimeoutIntent = new Intent(
                                Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
                        rollbackTimeoutIntent.putExtra(
                                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
                                enableRollbackToken);
                        rollbackTimeoutIntent.addFlags(
                                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
                                android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
                    }
                    break;
                }
                ···

params.handleRollbackEnabled();方法:

        void handleRollbackEnabled() {
            // TODO(ruhler) b/112431924: Consider halting the install if we
            // couldn't enable rollback.
            mEnableRollbackCompleted = true;
            handleReturnCode();
        }

再看handleReturnCode();方法:

        @Override
        void handleReturnCode() {
            //由于上面的36和37都執(zhí)行了嫌褪,所以這個true
            if (mVerificationCompleted && mEnableRollbackCompleted) {
                if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
                    String packageName = "";
                    try {
                        PackageLite packageInfo =
                                new PackageParser().parsePackageLite(origin.file, 0);//***38***
                        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) {
                    //***39***
                    mRet = mArgs.copyApk();
                }
                //***40***復制完成之后進入下一階段
                processPendingInstall(mArgs, mRet);
            }
        }

看FileInstallArgs類的copyApk()方法:

        int copyApk() {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
            try {
                return doCopyApk();//***41***
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        }

        private int doCopyApk() {
            // 前邊計算了一大通,最終還是以origin.staged為準
            if (origin.staged) {
                //如果已經(jīng)copy過了胚股,直接返回INSTALL_SUCCEEDED笼痛,在Android10里其實前面是已經(jīng)copy過了
                if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
                codeFile = origin.file;
                resourceFile = origin.file;
                return PackageManager.INSTALL_SUCCEEDED;
            }

            try {
                // 2 instant app 和external 計算安裝位置并拷貝
                final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
                final File tempDir =
                        mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);//***42***
                codeFile = tempDir;
                resourceFile = tempDir;
            } catch (IOException e) {
                Slog.w(TAG, "Failed to create copy file: " + e);
                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
            }

            int ret = PackageManagerServiceUtils.copyPackage(
                    origin.file.getAbsolutePath(), codeFile);//***43***
            if (ret != PackageManager.INSTALL_SUCCEEDED) {
                Slog.e(TAG, "Failed to copy package");
                return ret;
            }

            //3 拷貝lib目錄
            final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
            NativeLibraryHelper.Handle handle = null;
            try {
                handle = NativeLibraryHelper.Handle.create(codeFile);
                ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, abiOverride);//***44***
            } catch (IOException e) {
                Slog.e(TAG, "Copying native libraries failed", e);
                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
            } finally {
                IoUtils.closeQuietly(handle);//***45***
            }

            return ret;
        }

由于之前PackageInstallerSession已經(jīng)完成了copy動作(即origin.staged=true),所以這個方法會直接返回琅拌。當然晃痴,也許如果origin.staged=false:

  • 調用mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral)創(chuàng)建拷貝的文件位置,
      @Deprecated
      public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
          synchronized (mSessions) {
              try {
                  final int sessionId = allocateSessionIdLocked();
                  mLegacySessions.put(sessionId, true);
                  final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid);//***46***
                  prepareStageDir(sessionStageDir);//***47***
                  return sessionStageDir;
              } catch (IllegalStateException e) {
                  throw new IOException(e);
              }
          }
      }
    
      private File buildTmpSessionDir(int sessionId, String volumeUuid) {
          final File sessionStagingDir = getTmpSessionDir(volumeUuid);//***48***
          return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp");
      }
    
    可以看到buildTmpSessionDir()方法财忽,之前的PackageInstallerSession進行copy過程也調用PackageInstallerService的createSession()然后調用到buildTmpSessionDir()
  • 調用PackageManagerServiceUtils.copyPackage(origin.file.getAbsolutePath(), codeFile)執(zhí)行copy工作泣侮,
      public static int copyPackage(String packagePath, File targetDir) {
          if (packagePath == null) {
              return PackageManager.INSTALL_FAILED_INVALID_URI;
          }
    
          try {
              final File packageFile = new File(packagePath);
              final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0);
              // 基礎apk拷貝
              copyFile(pkg.baseCodePath, targetDir, "base.apk");//***49***
              // split apk拷貝
              if (!ArrayUtils.isEmpty(pkg.splitNames)) {
                  for (int i = 0; i < pkg.splitNames.length; i++) {
                      copyFile(pkg.splitCodePaths[i], targetDir,
                              "split_" + pkg.splitNames[i] + ".apk");
                  }
              }
              return PackageManager.INSTALL_SUCCEEDED;
          } catch (PackageParserException | IOException | ErrnoException e) {
              Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
              return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
          }
      }
    
      private static void copyFile(String sourcePath, File targetDir, String targetName)
              throws ErrnoException, IOException {
          if (!FileUtils.isValidExtFilename(targetName)) {
              throw new IllegalArgumentException("Invalid filename: " + targetName);
          }
          Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
    
          final File targetFile = new File(targetDir, targetName);
          // 這里和PackagerInstallerSession的doWriteInternal()方法相似即彪,0644是本用戶能讀寫,其他和同一個用戶組只能讀
          final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
                  O_RDWR | O_CREAT, 0644);
          Os.chmod(targetFile.getAbsolutePath(), 0644);
          FileInputStream source = null;
          try {
              source = new FileInputStream(sourcePath);
              FileUtils.copy(source.getFD(), targetFd);
          } finally {
              IoUtils.closeQuietly(source);
          }
      }
    
  • 調用NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,abiOverride);對native libraries進行Unpack處理:
      public static int copyNativeBinariesWithOverride(Handle handle, File libraryRoot,
              String abiOverride) {
          try {
              if (handle.multiArch) {
                  // Warn if we've set an abiOverride for multi-lib packages..
                  // By definition, we need to copy both 32 and 64 bit libraries for
                  // such packages.
                  if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
                      Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
                  }
    
                  int copyRet = PackageManager.NO_NATIVE_LIBRARIES;
                  if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
                      copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot,
                              Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */);
                      if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
                              copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
                          Slog.w(TAG, "Failure copying 32 bit native libraries; copyRet=" +copyRet);
                          return copyRet;
                      }
                  }
    
                  if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
                      //***50***
                      copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot,
                              Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */);
                      if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
                              copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
                          Slog.w(TAG, "Failure copying 64 bit native libraries; copyRet=" +copyRet);
                          return copyRet;
                      }
                  }
              } else {
                  String cpuAbiOverride = null;
                  if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
                      cpuAbiOverride = null;
                  } else if (abiOverride != null) {
                      cpuAbiOverride = abiOverride;
                  }
    
                  String[] abiList = (cpuAbiOverride != null) ?
                          new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
                  if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
                          hasRenderscriptBitcode(handle)) {
                      abiList = Build.SUPPORTED_32_BIT_ABIS;
                  }
    
                  int copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, abiList,
                          true /* use isa specific subdirs */);
                  if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
                      Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]");
                      return copyRet;
                  }
              }
    
              return PackageManager.INSTALL_SUCCEEDED;
          } catch (IOException e) {
              Slog.e(TAG, "Copying native libraries failed", e);
              return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
          }
      }
    

PackageInstallerSession的extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)方法也調用NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir, abiOverride);對native libraries進行copy處理活尊。

下一階段是APK的加載流程

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末隶校,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蛹锰,更是在濱河造成了極大的恐慌深胳,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铜犬,死亡現(xiàn)場離奇詭異舞终,居然都是意外死亡轻庆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門敛劝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來余爆,“玉大人,你說我怎么就攤上這事夸盟《攴剑” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵上陕,是天一觀的道長桩砰。 經(jīng)常有香客問我,道長释簿,這世上最難降的妖魔是什么亚隅? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮辕万,結果婚禮上枢步,老公的妹妹穿的比我還像新娘。我一直安慰自己渐尿,他們只是感情好醉途,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著砖茸,像睡著了一般隘擎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凉夯,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天货葬,我揣著相機與錄音,去河邊找鬼劲够。 笑死震桶,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的征绎。 我是一名探鬼主播蹲姐,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼人柿!你這毒婦竟也來了柴墩?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤凫岖,失蹤者是張志新(化名)和其女友劉穎江咳,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哥放,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡歼指,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年爹土,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片东臀。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡着饥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惰赋,到底是詐尸還是另有隱情宰掉,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布赁濒,位于F島的核電站轨奄,受9級特大地震影響,放射性物質發(fā)生泄漏拒炎。R本人自食惡果不足惜挪拟,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望击你。 院中可真熱鬧玉组,春花似錦、人聲如沸丁侄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸿摇。三九已至石景,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拙吉,已是汗流浹背潮孽。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留筷黔,地道東北人往史。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像佛舱,于是被迫代替她去往敵國和親怠堪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容