PackageManagerService分析

1.PackageManagerService的初始化在SystemServer中進(jìn)行

// Start the package manager.
        traceBeginAndSlog("StartPackageManagerService");
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

2.PackageManagerService.main(Context c, Installer i,boolean factoryTest, boolean onlyCore)

public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        ServiceManager.addService("package", m);
        return m;
    }

3.PackageManagerService構(gòu)造函數(shù)超級長,這里一個(gè)點(diǎn)一個(gè)點(diǎn)粗略來過一下

3.1首先是Setting的相關(guān)信息處理
// 存儲系統(tǒng)運(yùn)行過程中的一些設(shè)置信息
mSettings = new Settings(mPackages);
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
3.2 Setting構(gòu)造函數(shù):主要是一些文件初始化工作
Settings(Object lock) {
        // Environment.getDataDirectory() : /data
        this(Environment.getDataDirectory(), lock);
    }

    Settings(File dataDir, Object lock) {
        mLock = lock;

        mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);

        mSystemDir = new File(dataDir, "system");// /data/system
        mSystemDir.mkdirs();
        FileUtils.setPermissions(mSystemDir.toString(),
                FileUtils.S_IRWXU|FileUtils.S_IRWXG
                |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                -1, -1);
        // /data/system/packages.xml
        mSettingsFilename = new File(mSystemDir, "packages.xml");
        // /data/system/packages-backup.xml
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
        // /data/system/packages.list
        mPackageListFilename = new File(mSystemDir, "packages.list");
        FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

        // Deprecated: Needed for migration
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
    }
3.3 Settings.addSharedUserLPw()
/**
    *   name = "android.uid.system", 
    *   uid = Process.SYSTEM_UID(1000),
    *   pkgFlags = ApplicationInfo.FLAG_SYSTEM ,表示該應(yīng)用安裝在系統(tǒng)進(jìn)程中,屬于系統(tǒng)應(yīng)用
    *   pkgPrivateFlags = ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
    */
    SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
    // mSharedUsers:ArrayMap<String, SharedUserSetting> 是一個(gè)Map,key值為uid字符竄描述,value為SharedUserSetting
        SharedUserSetting s = mSharedUsers.get(name);
        if (s != null) {// 從Map中直接取出來
            if (s.userId == uid) {
                return s;
            }
            PackageManagerService.reportSettingsProblem(Log.ERROR,
                    "Adding duplicate shared user, keeping first: " + name);
            return null;
        }
        // Map中沒有,生成一個(gè)
        s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
        s.userId = uid;
        if (addUserIdLPw(uid, s, name)) {
            mSharedUsers.put(name, s);
            return s;
        }
        return null;
    }
private boolean addUserIdLPw(int uid, Object obj, Object name) {
        if (uid > Process.LAST_APPLICATION_UID) {// uid > 19999
            return false;
        }

        if (uid >= Process.FIRST_APPLICATION_UID) {// uid >= 10000 && uid <= 19999-->普通APK所在的進(jìn)程UID
            int N = mUserIds.size();
            final int index = uid - Process.FIRST_APPLICATION_UID;
            while (index >= N) {
                mUserIds.add(null);
                N++;
            }
            if (mUserIds.get(index) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate user id: " + uid
                        + " name=" + name);
                return false;
            }
            mUserIds.set(index, obj);
        } else { // uid < 10000 && uid > 0-->系統(tǒng)APK所在的進(jìn)程UID
            if (mOtherUserIds.get(uid) != null) {
                PackageManagerService.reportSettingsProblem(Log.ERROR,
                        "Adding duplicate shared id: " + uid
                                + " name=" + name);
                return false;
            }
            mOtherUserIds.put(uid, obj);
        }
        return true;
    }

相關(guān)類圖:

QQ截圖20160805164615.png

上面這些到底在設(shè)置些啥信息呢?這個(gè)要從AndroidManifest.xml的<manifest>標(biāo)簽的android:sharedUserId配置說起,如果多個(gè)APK設(shè)置的android:sharedUserId都是一樣的話,那這些APK則具有相同的權(quán)限,可共享彼此的數(shù)據(jù),并且可運(yùn)行在同一個(gè)進(jìn)程當(dāng)中(<application>標(biāo)簽配置android:process為一樣即可);
SharedUserSetting這個(gè)類是用來保存共享數(shù)據(jù)的,其中的name屬性保存的就是sharedUserId指定的字符竄也就是共享用戶名,userId屬性存儲的是共享用戶UID,packages保存的就是sharedUserId配置為一樣的所有的APK信息。PackageSetting對應(yīng)的是其中某個(gè)APK相關(guān)信息。
Android系統(tǒng)中的UID,是用戶ID的縮寫,一般而言,每個(gè)進(jìn)程都會有一個(gè)UID,表示該進(jìn)程屬于哪個(gè)用戶,不同的用戶具有不同的權(quán)限,一個(gè)進(jìn)程也可以分屬不同的用戶組,表示每個(gè)用戶組具有相應(yīng)的權(quán)限。
這個(gè)怎么理解,拿Android來說,它分為系統(tǒng)進(jìn)程和應(yīng)用進(jìn)程,系統(tǒng)進(jìn)程對應(yīng)一個(gè)UID,某個(gè)應(yīng)用進(jìn)程對應(yīng)另外一個(gè)UID,系統(tǒng)進(jìn)程具有它自己的權(quán)限,應(yīng)用進(jìn)程對應(yīng)的也有它自己相應(yīng)的權(quán)限;對于系統(tǒng)進(jìn)程或是某個(gè)應(yīng)用進(jìn)程來說,它屬于本進(jìn)程的用戶組,它也可以屬于其他進(jìn)程中的某個(gè)用戶組(sharedUserId),比如framework-res.apk和SettingsProvider,它們都運(yùn)行在"system"進(jìn)程當(dāng)中,它們的android:sharedUserId都是"android.uid.system",這就意味著它們不但具有獲取它們各自本身的數(shù)據(jù)的權(quán)限,還具有獲取彼此共享數(shù)據(jù)的權(quán)限。假如還有某個(gè)APK設(shè)置的process也為system,但是沒有設(shè)置android:sharedUserId,那么它具有的權(quán)限就是只能訪問它自己的數(shù)據(jù)了。
以上,就是Settings簡要分析,總結(jié)來說,就是對幾個(gè)特殊的將來可能用來保存共享數(shù)據(jù)的進(jìn)程進(jìn)行初始化工作,比如該進(jìn)程具有什么權(quán)限,支持什么功能等等。

3.2系統(tǒng)權(quán)限配置信息讀取和package.xml文件掃描解析
//......
// SystemConfig這個(gè)類掃描/etc/sysconfig和/etc/permissions/目錄,
//解析XML文件獲取到系統(tǒng)所有權(quán)限配置信息。
            ArrayMap<String, SystemConfig.PermissionEntry> permConfig
                    = systemConfig.getPermissions();
//掃描解析/data/system/package.xml文件,這個(gè)文件保存的是安裝包對應(yīng)的相關(guān)信息:包名、權(quán)限、簽名等
//當(dāng)有程序安裝、卸載、更新等操作時(shí),這個(gè)文件會發(fā)生變更
 mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
                    mSdkVersion, mOnlyCore);
3.3 相關(guān)jar和apk dex優(yōu)化處理(/system/framework/目錄下相關(guān)的jar和apk)
// Set flag to monitor and not change apk file paths when
            // scanning install directories.
            final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;

            final ArraySet<String> alreadyDexOpted = new ArraySet<String>();

            /**
             * Add everything in the in the boot class path to the
             * list of process files because dexopt will have been run
             * if necessary during zygote startup.
             */
            final String bootClassPath = System.getenv("BOOTCLASSPATH");
            final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");

            if (bootClassPath != null) {
                String[] bootClassPathElements = splitString(bootClassPath, ':');
                for (String element : bootClassPathElements) {
                    alreadyDexOpted.add(element);
                }
            } else {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }

            if (systemServerClassPath != null) {
                String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
                for (String element : systemServerClassPathElements) {
                    alreadyDexOpted.add(element);
                }
            } else {
                Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
            }

            final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
            final String[] dexCodeInstructionSets =
                    getDexCodeInstructionSets(
                            allInstructionSets.toArray(new String[allInstructionSets.size()]));

            /**
             * Ensure all external libraries have had dexopt run on them.
             * 確保所有的依賴庫都進(jìn)行dex優(yōu)化
             */
            if (mSharedLibraries.size() > 0) {
                // NOTE: For now, we're compiling these system "shared libraries"
                // (and framework jars) into all available architectures. It's possible
                // to compile them only when we come across an app that uses them (there's
                // already logic for that in scanPackageLI) but that adds some complexity.
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
                        final String lib = libEntry.path;
                        if (lib == null) {
                            continue;
                        }

                        try {
                            int dexoptNeeded = DexFile.getDexOptNeeded(lib, dexCodeInstructionSet,
                                    "speed", false);
                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                alreadyDexOpted.add(lib);
                                mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
                                        dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
                            }
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Library not found: " + lib);
                        } catch (IOException e) {
                            Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                    + e.getMessage());
                        }
                    }
                }
            }
            // /system/framework/
            File frameworkDir = new File(Environment.getRootDirectory(), "framework");

            // Gross hack for now: we know this file doesn't contain any
            // code, so don't dexopt it to avoid the resulting log spew.
            // 該APK不含任何代碼,所以不需要進(jìn)行dex優(yōu)化,以減少啟動時(shí)間
            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");

            // Gross hack for now: we know this file is only part of
            // the boot class path for art, so don't dexopt it to
            // avoid the resulting log spew.
            alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");

            /**
             * There are a number of commands implemented in Java, which
             * we currently need to do the dexopt on so that they can be
             * run from a non-root shell.
             */
            String[] frameworkFiles = frameworkDir.list();// 獲取/system/framework/所有子目錄
            if (frameworkFiles != null) {
                // TODO: We could compile these only for the most preferred ABI. We should
                // first double check that the dex files for these commands are not referenced
                // by other system apps.
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    for (int i=0; i<frameworkFiles.length; i++) {
                        File libPath = new File(frameworkDir, frameworkFiles[i]);
                        String path = libPath.getPath();
                        // Skip the file if we already did it.
                        if (alreadyDexOpted.contains(path)) {
                            continue;
                        }
                        // Skip the file if it is not a type we want to dexopt.
                        // 只對APK文件和JAR文件進(jìn)行dex優(yōu)化處理
                        if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
                            continue;
                        }
                        try {
                            int dexoptNeeded = DexFile.getDexOptNeeded(path, dexCodeInstructionSet,
                                    "speed", false);
                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                // 對相關(guān)jar和apk文件進(jìn)行dex優(yōu)化
                                mInstaller.dexopt(path, Process.SYSTEM_UID, dexCodeInstructionSet,
                                        dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
                            }
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Jar not found: " + path);
                        } catch (IOException e) {
                            Slog.w(TAG, "Exception reading jar: " + path, e);
                        }
                    }
                }
            }

            final VersionInfo ver = mSettings.getInternalVersion();
            mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
            // when upgrading from pre-M, promote system app permissions from install to runtime
            // 當(dāng)版本升級到22的時(shí)候,權(quán)限從原來的安裝的時(shí)候就設(shè)置好變成在運(yùn)行給出提示讓用戶選擇是否允許相關(guān)操作
            mPromoteSystemApps =
                    mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;

            // save off the names of pre-existing system packages prior to scanning; we don't
            // want to automatically grant runtime permissions for new system apps
            if (mPromoteSystemApps) {
                Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
                while (pkgSettingIter.hasNext()) {
                    PackageSetting ps = pkgSettingIter.next();
                    if (isSystemApp(ps)) {
                        mExistingSystemPackages.add(ps.name);
                    }
                }
            }
3.4掃描指定目錄下的APK文件,然后解析APK文件
//......
// Find base frameworks (resource packages without code).
            // /system/framework/
            scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED,
                    scanFlags | SCAN_NO_DEX, 0);

// Collect ordinary system packages.
            // /system/app/ 系統(tǒng)應(yīng)用APK放置路徑
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

// 掃描解析/data/app/目錄下的APK,我們安裝的APK放在這個(gè)目錄下面
      scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
//......
/**
*掃描指定目錄下面的文件,獲取APK文件或是子目錄,
*然后通過scanPackageLI對APK文件或是子目錄進(jìn)行處理
*/
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
        final File[] files = dir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + dir);
            return;
        }

        if (DEBUG_PACKAGE_SCANNING) {
            Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }

        for (File file : files) {
            final boolean isPackage = (isApkFile(file) || file.isDirectory())
                    && !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {// APK文件或是目錄才會處理
                // Ignore entries which are not packages
                continue;
            }
            try {
                scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                        scanFlags, currentTime, null);
            } catch (PackageManagerException e) {
                Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());

                // Delete invalid userdata apps
                if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                        e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                    logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
                    if (file.isDirectory()) {
                        mInstaller.rmPackageDir(file.getAbsolutePath());
                    } else {
                        file.delete();
                    }
                }
            }
        }
    }
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
            long currentTime, UserHandle user) throws PackageManagerException {
        if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
        parseFlags |= mDefParseFlags;
        PackageParser pp = new PackageParser();
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setOnlyCoreApps(mOnlyCore);
        pp.setDisplayMetrics(mMetrics);

        if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
            parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
        }

        final PackageParser.Package pkg;
        try {
            // 對文件進(jìn)行解析處理,APK數(shù)據(jù)保存在PackageParser.Package 對象中
            pkg = pp.parsePackage(scanFile, parseFlags);
        } catch (PackageParserException e) {
            throw PackageManagerException.from(e);
        }

      //APK更新升級相關(guān)邏輯
      //......
}

PackageParser.parsePackage()

public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        if (packageFile.isDirectory()) {// 包含APK的路徑 比如/data/app/xxxx
            return parseClusterPackage(packageFile, flags);
        } else {//直接解析一個(gè)APK文件,比如/system/framework/framework-res.apk
            return parseMonolithicPackage(packageFile, flags);
        }
    }

先看直接解析APK的方法:parseMonolithicPackage()

public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        if (mOnlyCoreApps) {
            final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
            if (!lite.coreApp) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                        "Not a coreApp: " + apkFile);
            }
        }

        // AssetManager初始化
        final AssetManager assets = new AssetManager();
        try {
            final Package pkg = parseBaseApk(apkFile, assets, flags);
            pkg.codePath = apkFile.getAbsolutePath();
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
    }

創(chuàng)建了一個(gè)AssetManager對象,然后通過parseBaseApk()來解析APK文件,parseBaseApk主要是對AndroidManifest.xml文件進(jìn)行解析,然后把解析后的數(shù)據(jù)保存到Package中,詳細(xì)的解析過程這里略過,相關(guān)的數(shù)據(jù)保存對象如下圖:

QQ截圖20160811114726.png
3.5 對解析APK獲取的PackageParser.Package配置進(jìn)程相關(guān)信息,填充3.1中的Settings信息,最后保存到ArrayMap<String, PackageParser.Package> mPackages這個(gè)Map中。
3.6 packagemanagerservice構(gòu)造函數(shù)主要的工作總結(jié)如下:

1)對特定的一些系統(tǒng)進(jìn)程信息進(jìn)行設(shè)置處理,保存到Settings中;
2)通過解析/etc/permissions下的相關(guān)xml文件取得系統(tǒng)相關(guān)權(quán)限、系統(tǒng)具備的相關(guān)功能等信息;
3)通過解析/data/system/package.xml文件獲取已安裝應(yīng)用相關(guān)信息;
4)對相關(guān)的apk和jar進(jìn)行dex優(yōu)化處理,主要是/system/framework/目錄下的相關(guān)jar和apk,framework-res.apk就放置在該目錄下面;
5)解析特定目錄下的APK文件(主要是解析AndroidManifest.xml),獲取APK相關(guān)信息,保存到PackageParser.Package這個(gè)對象中;
6)依據(jù)sharedUserId這個(gè)配置來確定APK運(yùn)行在哪個(gè)進(jìn)程,然后把運(yùn)行的相關(guān)進(jìn)程信息加入到Settings中,使得系統(tǒng)能夠知道每個(gè)APK運(yùn)行在哪個(gè)進(jìn)程里面。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,786評論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,964評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,354評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,554評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,106評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,918評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,093評論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,342評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,839評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,107評論 2 375

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