Android DropboxManager介紹

最近工作中需要對(duì)Crash的應(yīng)用進(jìn)行處理驻债,看了下Android有提供相關(guān)的Manager對(duì)各類異常進(jìn)行記錄阅畴,也就是DropboxManager柄慰。

什么是 DropBoxManager ?

Enqueues chunks of data (from various sources – application crashes, kernel log records, etc.). The queue is size bounded and will drop old data if the enqueued data exceeds the maximum size. You can think of this as a persistent, system-wide, blob-oriented “l(fā)ogcat”.DropBoxManager entries are not sent anywhere directly, but other system. services and debugging tools may scan and upload entries for processing

DropBoxManager 是 Android 在 Froyo(API level 8) 引入的用來(lái)持續(xù)化存儲(chǔ)系統(tǒng)數(shù)據(jù)的機(jī)制, 主要用于記錄 Android 運(yùn)行過(guò)程中, 內(nèi)核, 系統(tǒng)進(jìn)程, 用戶進(jìn)程等出現(xiàn)嚴(yán)重問(wèn)題時(shí)的 log, 可以認(rèn)為這是一個(gè)可持續(xù)存儲(chǔ)的系統(tǒng)級(jí)別的 logcat.

我們可以通過(guò)用參數(shù) DROPBOX_SERVICE 調(diào)用 getSystemService(String) 來(lái)獲得這個(gè)服務(wù), 并查詢出所有存儲(chǔ)在 DropBoxManager 里的系統(tǒng)錯(cuò)誤記錄.

Android 缺省能記錄哪些系統(tǒng)錯(cuò)誤 ?

具體能記錄哪些系統(tǒng)錯(cuò)誤嫉到,官方的文檔中沒(méi)有提及梦湘,我們?cè)贒ropboxManager.java源代碼文件中的EXTRA_TAG(tag)中找到相關(guān)信息瞎颗。

  • crash (應(yīng)用程序強(qiáng)制關(guān)閉, Force Close)
    當(dāng)Java層遇到未被 catch 的例外時(shí), ActivityManagerService 會(huì)記錄一次 crash到 DropBoxManager中, 并彈出 Force Close對(duì)話框提示用戶.
 /**
 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
 * The application process will exit immediately after this call returns.
 * @param app object of the crashing app, null for the system server
 * @param crashInfo describing the exception
 */
 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
       ProcessRecord r = findAppProcess(app, "Crash");
       final String processName = app == null ? "system_server": (r == null ? "unknown" : r.processName);
       handleApplicationCrashInner("crash", r, processName, crashInfo);
 }

 /* Native crash reporting uses this inner version because it needs to be somewhat
 * decoupled from the AM-managed cleanup lifecycle
 */
 void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,ApplicationErrorReport.CrashInfo crashInfo) {
      EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
      UserHandle.getUserId(Binder.getCallingUid()), processName, r == null ? -1 : r.info.flags,crashInfo.exceptionClassName,crashInfo.exceptionMessage,crashInfo.throwFileName,crashInfo.throwLineNumber);

      addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);

      crashApplication(r, crashInfo);
 }
  • anr (應(yīng)用程序沒(méi)響應(yīng), Application Not Responding, ANR)
    當(dāng)應(yīng)用程序的主線程(UI線程)長(zhǎng)時(shí)間未能得到響應(yīng)時(shí), ActivityManagerService 會(huì)記錄一次 anr到 DropBoxManager中, 并彈出 Application Not Responding對(duì)話框提示用戶.
final void appNotResponding(ProcessRecord app, ActivityRecord activity, ActivityRecord parent, boolean aboveSystem, final String annotation) { 
      //...... 
      addErrorToDropBox("anr", app, app.processName, activity, parent, annotation, cpuInfo, tracesFile, null);
      //......
}
  • wtf (What a Terrible Failure)
    ‘a(chǎn)ndroid.util.Log’ 類提供了靜態(tài)的 wtf 函數(shù), 應(yīng)用程序可以在代碼中用來(lái)主動(dòng)報(bào)告一個(gè)不應(yīng)當(dāng)發(fā)生的情況. 依賴于系統(tǒng)設(shè)置, 這個(gè)函數(shù)會(huì)通過(guò) ActivityManagerService 增加一個(gè) wtf 記錄到 DropBoxManager中, 并/或終止當(dāng)前應(yīng)用程序進(jìn)程.
    /**
     * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
     * @param app object of the crashing app, null for the system server
     * @param tag reported by the caller
     * @param system whether this wtf is coming from the system
     * @param crashInfo describing the context of the error
     * @return true if the process should exit immediately (WTF is fatal)
     */
    public boolean handleApplicationWtf(final IBinder app, final String tag, boolean system,
            final ApplicationErrorReport.CrashInfo crashInfo) {
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
        if (system) {
            // If this is coming from the system, we could very well have low-level
            // system locks held, so we want to do this all asynchronously.  And we
            // never want this to become fatal, so there is that too.
            mHandler.post(new Runnable() {
                @Override public void run() {
                    handleApplicationWtfInner(callingUid, callingPid, app, tag, crashInfo);
                }
            });
            return false;
        }
        final ProcessRecord r = handleApplicationWtfInner(callingUid, callingPid, app, tag,
                crashInfo);
        if (r != null && r.pid != Process.myPid() &&
                Settings.Global.getInt(mContext.getContentResolver(),
                        Settings.Global.WTF_IS_FATAL, 0) != 0) {
            crashApplication(r, crashInfo);
            return true;
        } else {
            return false;
        }
    }
    ProcessRecord handleApplicationWtfInner(int callingUid, int callingPid, IBinder app, String tag,
            final ApplicationErrorReport.CrashInfo crashInfo) {
        final ProcessRecord r = findAppProcess(app, "WTF");
        final String processName = app == null ? "system_server"
                : (r == null ? "unknown" : r.processName);
        EventLog.writeEvent(EventLogTags.AM_WTF, UserHandle.getUserId(callingUid), callingPid,
                processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);

        addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo);

        return r;
    }
  • strict_mode (StrictMode Violation)
    StrictMode (嚴(yán)格模式), 顧名思義, 就是在比正常模式檢測(cè)得更嚴(yán)格, 通常用來(lái)監(jiān)測(cè)不應(yīng)當(dāng)在主線程執(zhí)行的網(wǎng)絡(luò), 文件等操作. 任何 StrictMode 違例都會(huì)被 ActivityManagerService 在 DropBoxManager 中記錄為一次 strict_mode違例.

    public void handleApplicationStrictModeViolation(
            IBinder app,
            int violationMask,
            StrictMode.ViolationInfo info) {
        ProcessRecord r = findAppProcess(app, "StrictMode");
        if (r == null) {
            return;
        }
        if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
            Integer stackFingerprint = info.hashCode();
            boolean logIt = true;
            synchronized (mAlreadyLoggedViolatedStacks) {
                if (mAlreadyLoggedViolatedStacks.contains(stackFingerprint)) {
                    logIt = false;
                    // TODO: sub-sample into EventLog for these, with
                    // the info.durationMillis?  Then we'd get
                    // the relative pain numbers, without logging all
                    // the stack traces repeatedly.  We'd want to do
                    // likewise in the client code, which also does
                    // dup suppression, before the Binder call.
                } else {
                    if (mAlreadyLoggedViolatedStacks.size() >= MAX_DUP_SUPPRESSED_STACKS) {
                        mAlreadyLoggedViolatedStacks.clear();
                    }
                    mAlreadyLoggedViolatedStacks.add(stackFingerprint);
                }
            }
            if (logIt) {
                logStrictModeViolationToDropBox(r, info);
            }
        }
    //......
}
// Depending on the policy in effect, there could be a bunch of
    // these in quick succession so we try to batch these together to
    // minimize disk writes, number of dropbox entries, and maximize
    // compression, by having more fewer, larger records.
    private void logStrictModeViolationToDropBox(
            ProcessRecord process,
            StrictMode.ViolationInfo info) {
        if (info == null) {
            return;
        }
        final boolean isSystemApp = process == null ||
                (process.info.flags & (ApplicationInfo.FLAG_SYSTEM |
                                       ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;
        final String processName = process == null ? "unknown" : process.processName;
        final String dropboxTag = isSystemApp ? "system_app_strictmode" : "data_app_strictmode";
        final DropBoxManager dbox = (DropBoxManager)
                mContext.getSystemService(Context.DROPBOX_SERVICE);
        // Exit early if the dropbox isn't configured to accept this report type.
        if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
        boolean bufferWasEmpty;
        boolean needsFlush;
        final StringBuilder sb = isSystemApp ? mStrictModeBuffer : new StringBuilder(1024);
        synchronized (sb) {
            bufferWasEmpty = sb.length() == 0;
            appendDropBoxProcessHeaders(process, processName, sb);
            sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
            sb.append("System-App: ").append(isSystemApp).append("\n");
            sb.append("Uptime-Millis: ").append(info.violationUptimeMillis).append("\n");
            if (info.violationNumThisLoop != 0) {
                sb.append("Loop-Violation-Number: ").append(info.violationNumThisLoop).append("\n");
            }
            if (info.numAnimationsRunning != 0) {
                sb.append("Animations-Running: ").append(info.numAnimationsRunning).append("\n");
            }
            if (info.broadcastIntentAction != null) {
                sb.append("Broadcast-Intent-Action: ").append(info.broadcastIntentAction).append("\n");
            }
            if (info.durationMillis != -1) {
                sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
            }
            if (info.numInstances != -1) {
                sb.append("Instance-Count: ").append(info.numInstances).append("\n");
            }
            if (info.tags != null) {
                for (String tag : info.tags) {
                    sb.append("Span-Tag: ").append(tag).append("\n");
                }
            }
            sb.append("\n");
            if (info.crashInfo != null && info.crashInfo.stackTrace != null) {
                sb.append(info.crashInfo.stackTrace);
            }
            sb.append("\n");
            // Only buffer up to ~64k.  Various logging bits truncate
            // things at 128k.
            needsFlush = (sb.length() > 64 * 1024);
        }
        // Flush immediately if the buffer's grown too large, or this
        // is a non-system app.  Non-system apps are isolated with a
        // different tag & policy and not batched.
        //
        // Batching is useful during internal testing with
        // StrictMode settings turned up high.  Without batching,
        // thousands of separate files could be created on boot.
        if (!isSystemApp || needsFlush) {
            new Thread("Error dump: " + dropboxTag) {
                @Override
                public void run() {
                    String report;
                    synchronized (sb) {
                        report = sb.toString();
                        sb.delete(0, sb.length());
                        sb.trimToSize();
                    }
                    if (report.length() != 0) {
                        dbox.addText(dropboxTag, report);
                    }
                }
            }.start();
            return;
        }
        // System app batching:
        if (!bufferWasEmpty) {
            // An existing dropbox-writing thread is outstanding, so
            // we don't need to start it up.  The existing thread will
            // catch the buffer appends we just did.
            return;
        }
        // Worker thread to both batch writes and to avoid blocking the caller on I/O.
        // (After this point, we shouldn't access AMS internal data structures.)
        new Thread("Error dump: " + dropboxTag) {
            @Override
            public void run() {
                // 5 second sleep to let stacks arrive and be batched together
                try {
                    Thread.sleep(5000);  // 5 seconds
                } catch (InterruptedException e) {}
                String errorReport;
                synchronized (mStrictModeBuffer) {
                    errorReport = mStrictModeBuffer.toString();
                    if (errorReport.length() == 0) {
                        return;
                    }
                    mStrictModeBuffer.delete(0, mStrictModeBuffer.length());
                    mStrictModeBuffer.trimToSize();
                }
                dbox.addText(dropboxTag, errorReport);
            }
        }.start();
    }
  • lowmem (低內(nèi)存)
    在內(nèi)存不足的時(shí)候, Android 會(huì)終止后臺(tái)應(yīng)用程序來(lái)釋放內(nèi)存, 但如果沒(méi)有后臺(tái)應(yīng)用程序可被釋放時(shí),ActivityManagerService 就會(huì)在 DropBoxManager 中記錄一次 lowmem.
    public void handleMessage(Message msg) {
        switch (msg.what) {
        //...
        case REPORT_MEM_USAGE: {
            //......
            Thread thread = new Thread() {
                @Override public void run() {
                    StringBuilder dropBuilder = new StringBuilder(1024);
                    StringBuilder logBuilder = new StringBuilder(1024);
                    //......
                    addErrorToDropBox("lowmem", null, "system_server", null,
                            null, tag.toString(), dropBuilder.toString(), null, null);
                    //......
                }
            };
            thread.start();
            break;
        }
        //......
    }
  • watchdog
    如果 WatchDog 監(jiān)測(cè)到系統(tǒng)進(jìn)程(system_server)出現(xiàn)問(wèn)題, 會(huì)增加一條 watchdog記錄到 DropBoxManager 中, 并終止系統(tǒng)進(jìn)程的執(zhí)行.
/** This class calls its monitor every minute. Killing this process if they don't return **/
public class Watchdog extends Thread {
    //......
    @Override
    public void run() {
        boolean waitedHalf = false;
        while (true) {
            //......

            // If we got here, that means that the system is most likely hung.
            // First collect stack traces from all threads of the system process.
            // Then kill this process so that the system will restart.

            //......

            // Try to add the error to the dropbox, but assuming that the ActivityManager
            // itself may be deadlocked.  (which has happened, causing this statement to
            // deadlock and the watchdog as a whole to be ineffective)
            Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
                    public void run() {
                        mActivity.addErrorToDropBox(
                                "watchdog", null, "system_server", null, null,
                                name, null, stack, null);
                    }
                };
            dropboxThread.start();
            try {
                dropboxThread.join(2000);  // wait up to 2 seconds for it to return.
            } catch (InterruptedException ignored) {}

            //......
        }
    }

    //......
}
  • netstats_error
    NetworkStatsService 負(fù)責(zé)收集并持久化存儲(chǔ)網(wǎng)絡(luò)狀態(tài)的統(tǒng)計(jì)數(shù)據(jù), 當(dāng)遇到明顯的網(wǎng)絡(luò)狀態(tài)錯(cuò)誤時(shí), 它會(huì)增加一條 netstats_error 記錄到 DropBoxManager.
  • BATTERY_DISCHARGE_INFO
    BatteryService 負(fù)責(zé)檢測(cè)充電狀態(tài), 并更新手機(jī)電池信息. 當(dāng)遇到明顯的 discharge 事件, 它會(huì)增加一條 BATTERY_DISCHARGE_INFO 記錄到 DropBoxManager.
  • 系統(tǒng)服務(wù)(System Serve)啟動(dòng)完成后的檢測(cè)
    系統(tǒng)服務(wù)(System Serve)啟動(dòng)完成后會(huì)進(jìn)行一系列自檢, 包括:
    -- 開(kāi)機(jī)
    每次開(kāi)機(jī)都會(huì)增加一條 SYSTEM_BOOT 記錄.
    -- System Server 重啟
    如果系統(tǒng)服務(wù)(System Server)不是開(kāi)機(jī)后的第一次啟動(dòng), 會(huì)增加一條 SYSTEM_RESTART 記錄, 正常情況下系統(tǒng)服務(wù)(System Server)在一次開(kāi)機(jī)中只會(huì)啟動(dòng)一次, 啟動(dòng)第二次就意味著 bug.
    -- Kernel Panic (內(nèi)核錯(cuò)誤)
    發(fā)生 Kernel Panic 時(shí), Kernel 會(huì)記錄一些 log 信息到文件系統(tǒng), 因?yàn)?Kernel 已經(jīng)掛掉了, 當(dāng)然這時(shí)不可能有其他機(jī)會(huì)來(lái)記錄錯(cuò)誤信息了. 唯一能檢測(cè) Kernel Panic 的辦法就是在手機(jī)啟動(dòng)后檢查這些 log 文件是否存在, 如果存在則意味著上一次手機(jī)是因?yàn)?Kernel Panic 而宕機(jī), 并記錄這些日志到 DropBoxManager 中. DropBoxManager 記錄 TAG 名稱和對(duì)應(yīng)的文件名分別是:
    SYSTEM_LAST_KMSG, 如果 /proc/last_kmsg 存在.
    APANIC_CONSOLE, 如果 /data/dontpanic/apanic_console 存在.
    APANIC_THREADS, 如果 /data/dontpanic/apanic_threads 存在.
    -- 系統(tǒng)恢復(fù)(System Recovery)
    通過(guò)檢測(cè)文件 /cache/recovery/log 是否存在來(lái)檢測(cè)設(shè)備是否因?yàn)橄到y(tǒng)恢復(fù)而重啟, 并增加一條 SYSTEM_RECOVERY_LOG 記錄到 DropBoxManager 中.
private void logBootEvents(Context ctx) throws IOException {
    final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
    final SharedPreferences prefs = ctx.getSharedPreferences("log_files", Context.MODE_PRIVATE);
    final String headers = new StringBuilder(512)
        .append("Build: ").append(Build.FINGERPRINT).append("\n")
        .append("Hardware: ").append(Build.BOARD).append("\n")
        .append("Revision: ")
        .append(SystemProperties.get("ro.revision", "")).append("\n")
        .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
        .append("Radio: ").append(Build.RADIO).append("\n")
        .append("Kernel: ")
        .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
        .append("\n").toString();

    String recovery = RecoverySystem.handleAftermath();
    if (recovery != null && db != null) {
        db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
    }

    if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
        String now = Long.toString(System.currentTimeMillis());
        SystemProperties.set("ro.runtime.firstboot", now);
        if (db != null) db.addText("SYSTEM_BOOT", headers);

        // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
        addFileToDropBox(db, prefs, headers, "/proc/last_kmsg",
                -LOG_SIZE, "SYSTEM_LAST_KMSG");
        addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
                -LOG_SIZE, "SYSTEM_RECOVERY_LOG");
        addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
                -LOG_SIZE, "APANIC_CONSOLE");
        addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_threads",
                -LOG_SIZE, "APANIC_THREADS");
    } else {
        if (db != null) db.addText("SYSTEM_RESTART", headers);
    }

    // Scan existing tombstones (in case any new ones appeared)
    File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
    for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
        addFileToDropBox(db, prefs, headers, tombstoneFiles[i].getPath(),
                LOG_SIZE, "SYSTEM_TOMBSTONE");
    }

    // Start watching for new tombstone files; will record them as they occur.
    // This gets registered with the singleton file observer thread.
    sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CLOSE_WRITE) {
        @Override
        public void onEvent(int event, String path) {
            try {
                String filename = new File(TOMBSTONE_DIR, path).getPath();
                addFileToDropBox(db, prefs, headers, filename, LOG_SIZE, "SYSTEM_TOMBSTONE");
            } catch (IOException e) {
                Slog.e(TAG, "Can't log tombstone", e);
            }
        }
    };

    sTombstoneObserver.startWatching();
}
  • SYSTEM_TOMBSTONE (Native 進(jìn)程的崩潰)
    Tombstone 是 Android 用來(lái)記錄 native 進(jìn)程崩潰的 core dump日志, 系統(tǒng)服務(wù)在啟動(dòng)完成后會(huì)增加一個(gè) Observer 來(lái)偵測(cè) tombstone 日志文件的變化, 每當(dāng)生成新的 tombstone文件, 就會(huì)增加一條 SYSTEM_TOMBSTONE記錄到 DropBoxManager 中.
    DropBoxManager 如何存儲(chǔ)記錄數(shù)據(jù) ?
    DropBoxManager 使用的是文件存儲(chǔ), 所有的記錄都存儲(chǔ)在 /data/system/dropbox目錄中, 一條記錄就是一個(gè)文件, 當(dāng)文本文件的尺寸超過(guò)文件系統(tǒng)的最小區(qū)塊尺寸后, DropBoxManager 還會(huì)自動(dòng)壓縮該文件, 通常文件名以調(diào)用 DropBoxManager 的 TAG 參數(shù)開(kāi)頭.
$ adb shell ls -l /data/system/dropbox
-rw------- system   system        258 2012-11-21 11:36 SYSTEM_RESTART@1353469017940.txt
-rw------- system   system         39 2012-11-21 11:40 event_data@1353469222884.txt
-rw------- system   system         39 2012-11-21 12:10 event_data@1353471022975.txt
-rw------- system   system         34 2012-11-21 18:10 event_log@1353492624170.txt
-rw------- system   system         34 2012-11-21 18:40 event_log@1353494424296.txt
-rw------- system   system         34 2012-11-22 10:10 event_log@1353550227432.txt
-rw------- system   system       1528 2012-11-21 22:54 system_app_crash@1353509648395.txt
-rw------- system   system       1877 2012-11-21 11:36 system_app_strictmode@1353469014395.txt
-rw------- system   system       3724 2012-11-21 11:36 system_app_strictmode@1353469014924.txt.gz

如何利用 DropBoxManager ?

  • 利用 DropBoxManager 來(lái)記錄需要持久化存儲(chǔ)的錯(cuò)誤日志信息
    DropBoxManager 提供了 logcat 之外的另外一種錯(cuò)誤日志記錄機(jī)制, 程序可以在出錯(cuò)的時(shí)候自動(dòng)將相關(guān)信息記錄到 DropBoxManager 中. 相對(duì)于 logcat, DropBoxManager 更適合于程序的自動(dòng)抓錯(cuò), 避免人為因素而產(chǎn)生的錯(cuò)誤遺漏. 并且 DropBoxManager 是 Android 系統(tǒng)的公開(kāi)服務(wù), 相對(duì)于很多私有實(shí)現(xiàn), 出現(xiàn)兼容性問(wèn)題的幾率會(huì)大大降低.

  • 錯(cuò)誤自動(dòng)上報(bào)
    可以將 DropBoxManager 和設(shè)備的 BugReport 結(jié)合起來(lái), 實(shí)現(xiàn)自動(dòng)上報(bào)錯(cuò)誤到服務(wù)器. 每當(dāng)生成新的記錄, DropBoxManager 就會(huì)廣播一個(gè) DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED Intent, 設(shè)備的 BugReport 服務(wù)需要偵聽(tīng)這個(gè) Intent, 然后觸發(fā)錯(cuò)誤的自動(dòng)上報(bào).

參考
介紹 Android DropBoxManager Service
Android Official Site
DropBoxManager Overview
ActivityManager Service Overview
Android StrictMode Overview

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市捌议,隨后出現(xiàn)的幾起案子哼拔,更是在濱河造成了極大的恐慌,老刑警劉巖瓣颅,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件倦逐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡宫补,警方通過(guò)查閱死者的電腦和手機(jī)檬姥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)粉怕,“玉大人健民,你說(shuō)我怎么就攤上這事∑侗矗” “怎么了秉犹?”我有些...
    開(kāi)封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)稚晚。 經(jīng)常有香客問(wèn)我崇堵,道長(zhǎng),這世上最難降的妖魔是什么客燕? 我笑而不...
    開(kāi)封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任鸳劳,我火速辦了婚禮,結(jié)果婚禮上幸逆,老公的妹妹穿的比我還像新娘棍辕。我一直安慰自己,他們只是感情好还绘,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布楚昭。 她就那樣靜靜地躺著,像睡著了一般拍顷。 火紅的嫁衣襯著肌膚如雪抚太。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音尿贫,去河邊找鬼电媳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛庆亡,可吹牛的內(nèi)容都是我干的匾乓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼又谋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拼缝!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起彰亥,我...
    開(kāi)封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤咧七,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后任斋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體继阻,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年废酷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瘟檩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锦积,死狀恐怖芒帕,靈堂內(nèi)的尸體忽然破棺而出歉嗓,到底是詐尸還是另有隱情丰介,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布鉴分,位于F島的核電站哮幢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏志珍。R本人自食惡果不足惜橙垢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伦糯。 院中可真熱鬧柜某,春花似錦、人聲如沸敛纲。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)淤翔。三九已至翰绊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背监嗜。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工谐檀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人裁奇。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓桐猬,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親刽肠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子课幕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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

  • ```java /* * Copyright (C) 2006 The Android Open Source P...
    mrganer閱讀 1,135評(píng)論 0 50
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)五垮,斷路器乍惊,智...
    卡卡羅2017閱讀 134,626評(píng)論 18 139
  • 先Activity的抽象類 BaseActivity [java]view plaincopy /** *Acti...
    Zaker2Magic閱讀 972評(píng)論 0 0
  • 這段時(shí)間公司的項(xiàng)目業(yè)務(wù)改動(dòng),原來(lái)用的數(shù)據(jù)庫(kù)是mysql放仗,最近打算把部分業(yè)務(wù)相關(guān)的數(shù)據(jù)存在mongodb润绎,我需要做的...
    westinyang閱讀 925評(píng)論 0 0
  • 1.當(dāng)我覺(jué)得我自己走了99步,而他卻一步也未曾向我靠近的時(shí)候 2.對(duì)話只剩下:哦、好银室、恩涂佃、知道了 3.發(fā)現(xiàn)自己沒(méi)有...
    唯美感情學(xué)閱讀 205評(píng)論 0 1