Android APK安装流程(3)--Copy旧代码兼容

  • 第7步 开启真正的安装之路

在开启继上文中的分析之前,我来大体做个简单总结说明:
Android10的安装流程变化了不少,同样为了兼容之前的流程,导致代码里有很多不合理或者说重复判断的情况出现,甚至还有前后矛盾的地方。总体上Android 10 安装应用要考虑的因素比较多,有以下几个方面:

  • 1.系统应用只允许安装到/data分区。
  • 2.分区空间要足够。
  • 3.覆盖安装要保持和原有安装在同一个分区。
  • 4.是否允许第三方应用安装到/data分区。
  • 5.是否强制允许安装应用到外置存储。
  • 6.AndroidManifest.xml里面的installLocation 标签。auto, internalOnly,preferExternal

前面5点在上文的分析中基本上都有体现,也比较容易理解。这里我们着重说以下第6点,AndroidManifest。在Android10中,默认的installLocation是internalOnly, 也就是只允许应用安装到/data分区,但是需要考虑之前是否已经安装过这个应用,如果已经在其他分区安装过,则可能发生不兼容,auto 和 preferExternal都是参考值,目前Android已经不在允许将应用直接安装到主存储,只允许将应用安装到内置存储和内置扩展存储。这是基于安全考虑,另外其实目前的主存储也是从内置存储或者扩展的内置存储上使用fuse划分出来的一个目录,二者其实是共用存储空间的,所以安装到主存储上其实意义不大,所以preferExternal标签其实已经被架空。

说到代码架空,本文中分析的不少代码是为了兼容老流程为存在的,所以也有不少代码本来是被架空的,也就是很多逻辑其实是走不到的。

OK,我们继续!

上文我们说到在InstallInstalling的onResume()方法中主要对各种文件执行整理认证,剔除不必要的文件和逻辑,执行到最后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的区别
        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,并且更新进度条回调给正在监听的Activity
  • 3.执行extractNativeLibraries()方法,创建/data/app/vmdlsessionId.tmp/lib,copyNativeBinariesWithOverride并在这个文件下创建该系统支持的一系列的如64位,32位的arm-v7的so库保存目录
  • 4.把localObserver这个本地Binder作为参数调用PMS的installStage方法,此时安装步骤将会转移到PMS中。之后等到PMS到达了某个阶段就会回调到onPackageInstalled,从而得知PMS那边安装完成了。

makeSessionActiveLocked()执行完毕后可以获取到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);//发送INIT_COPY事件
    }

mHandler是PackageManagerService的内部类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();

代码走到这里我们发现2个abstract方法,所以我们需要研究HandlerParams这个类。HandlerParams是个抽象类,其有2个实现类InstallParams和MultiPackageInstallParams,MutilPackageInstallParams用于负责批量安装, InstallParams则负责单一安装, MutilPackageInstallParams的成员变量mChildParams指向多个InstallParams, 说明批量安装其实就是调用多个单一安装的实现的。从上文传递的属性我们可以看到执行的是单一安装也就是InstallParams,所以执行的是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.表示前边已经确定好了安装目录(\${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()函数确定推荐的安装位置。
            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将安装文件拷贝到临时目录,如果已经拷贝,则并不需要关心空间问题
            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系统中,并对存储空间是否足够进行判断,如果不够则进行内存释放。其实这个方法里执行的基本上都是无用代码,因为在之前我们因为分析到通过Session已经完成计算存储空间,释放内存等的操作。
    /**
     * 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最外层的数据.
            //拿到版本号,包名,包的路径等等不包含四大组件的基础信息。
            //和parseMonolithicPackageLite作用十分相似,核心还是遍历这个目录里面                
            //所有的apk文件,以splitName为key,ApkLite为value保存起来,
            //并且找出null为key对应的baseApk的value
            pkg = PackageParser.parsePackageLite(packageFile, 0);//***31***
            // 对安装后的包进行大小统计,计算结果是:
            // 安装后大小 = 每一个包安装路径下文件的大小(/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()的安装成功了,则会进行判断该包是否已经安装过且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系统中的包校验广播接受者;通过matchVerifiers()方法筛选出当前合适的包校验器;最后依次发送广播,让包校验接受者根据包名,versionCode,packageName,安装来源等信息进行校验.
  • 4.调用mContext.sendOrderedBroadcastAsUser()发送广播,验证完毕后,调用final Message msg = mHandler.obtainMessage(CHECK_PENDING_VERIFICATION);给mHandler发消息:
                ···
                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()发送广播,对Rollback(这个Rollback是什么?)进行验证。然后调用final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);给mHandler发消息:
                ···
                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都执行了,所以这个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) {
                //如果已经copy过了,直接返回INSTALL_SUCCEEDED,在Android10里其实前面是已经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已经完成了copy动作(即origin.staged=true),所以这个方法会直接返回。当然,也许如果origin.staged=false:

  • 调用mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral)创建拷贝的文件位置,
      @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)执行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的加载流程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容