高通平臺Android 12-Telephony之SIM卡初始化流程學習總結

本文代碼以高通平臺Android 12為分析對象岩调,可能會與Google原生AOSP有些許差異。

本文主要介紹UICC在Framework的初始化過程和SIM卡數(shù)據(jù)加載過程奶稠,可以幫助讀者分析一些關于SIM卡狀態(tài)與數(shù)據(jù)相關的問題。

在framework下UiccController.java開頭包含下面這段注釋捡遍,可以看出來UiccController就是管理Android SIM卡的控制器:

/**

 * This class is responsible for keeping all knowledge about

 * Universal Integrated Circuit Card (UICC), also know as SIM's,

 * in the system. It is also used as API to get appropriate

 * applications to pass them to phone and service trackers.

 *

 * UiccController is created with the call to make() function.

 * UiccController is a singleton and make() must only be called once

 * and throws an exception if called multiple times.

 *

 * Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed"

 * notifications. When such notification arrives UiccController will call

 * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS

 * request appropriate tree of uicc objects will be created.

 *

 * Following is class diagram for uicc classes:

 *

 *                       UiccController

 *                            #

 *                            |

 *                        UiccSlot[]

 *                            #

 *                            |

 *                        UiccCard

 *                            #

 *                            |

 *                       UiccProfile

 *                          #   #

 *                          |   ------------------

 *                    UiccCardApplication    CatService

 *                      #            #

 *                      |            |

 *                 IccRecords    IccFileHandler

 *                 ^ ^ ^           ^ ^ ^ ^ ^

 *    SIMRecords---- | |           | | | | ---SIMFileHandler

 *    RuimRecords----- |           | | | ----RuimFileHandler

 *    IsimUiccRecords---           | | -----UsimFileHandler

 *                                 | ------CsimFileHandler

 *                                 ----IsimFileHandler

 *

 * Legend: # stands for Composition

 *         ^ stands for Generalization

 *

 * See also {@link com.android.internal.telephony.IccCard}

 */

1.UiccController初始化

從下面的代碼可以看出锌订,UiccController屬于單例模式,只能創(chuàng)建一個實例画株,如果多次創(chuàng)建會拋出RuntimeException("UiccController.make() should only be called once")異常辆飘。

    /**

     * API to make UiccController singleton if not already created.

     */

    public static UiccController make(Context c) {

        synchronized (mLock) {

            if (mInstance != null) {

                throw new RuntimeException("UiccController.make() should only be called once");

            }

            mInstance = new UiccController(c);

            return mInstance;

        }

    }

UiccController的初始化是在Phone進程初始化的時候進行的,有關Phone進程初始化流程想了解的可以去查看相關代碼與文檔谓传,本文不詳細講解蜈项。

PhoneFactory調(diào)用makeDefaultPhone()時,會調(diào)用UiccController.make()創(chuàng)建UiccController實例:

    @UnsupportedAppUsage

    public static void makeDefaultPhone(Context context) {

 ...

 // Instantiate UiccController so that all other classes can just

                // call getInstance()

                sUiccController = UiccController.make(context);

 ...

 }

再來看看UiccController初始化的時候干了什么:

    private UiccController(Context c) {

        if (DBG) log("Creating UiccController");

        mContext = c;

        mCis = PhoneFactory.getCommandsInterfaces();  //獲取到RIL接口實例(RIL是Phone進程初始化時創(chuàng)建的) RIL implementation of the CommandsInterface.

        int numPhysicalSlots = c.getResources().getInteger(

                com.android.internal.R.integer.config_num_physical_slots);

        numPhysicalSlots = TelephonyProperties.sim_slots_count().orElse(numPhysicalSlots);

        if (DBG) {

            logWithLocalLog("config_num_physical_slots = " + numPhysicalSlots);

        }

        // Minimum number of physical slot count should be equals to or greater than phone count,

        // if it is less than phone count use phone count as physical slot count.

        if (numPhysicalSlots < mCis.length) {

            numPhysicalSlots = mCis.length; //如果定義的物理卡槽數(shù)量小于Phone進程實際創(chuàng)建的phone的數(shù)量续挟,那么就使用phone進程實際創(chuàng)建的phone的數(shù)量

        }

        mUiccSlots = new UiccSlot[numPhysicalSlots]; //根據(jù)物理卡槽的數(shù)量創(chuàng)建UiccSlot數(shù)組

        mPhoneIdToSlotId = new int[mCis.length]; //SlotId數(shù)組紧卒,index就是phoneId

        Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID);

        if (VDBG) logPhoneIdToSlotIdMapping();

        mRadioConfig = RadioConfig.getInstance(); //獲取到RadioConfig實例(RadioConfig是Phone進程初始化時創(chuàng)建的)

        mRadioConfig.registerForSimSlotStatusChanged(this, EVENT_SLOT_STATUS_CHANGED, null); //注冊EVENT_SLOT_STATUS_CHANGED事件監(jiān)聽

        for (int i = 0; i < mCis.length; i++) {//開始遍歷每個RIL對象進行SIM相關的事件注冊

            mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i);

            if (!StorageManager.inCryptKeeperBounce()) {

                mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);

            } else {

                mCis[i].registerForOn(this, EVENT_RADIO_ON, i);

            }

            mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);

            mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);

        }

        mLauncher = new UiccStateChangedLauncher(c, this); //初始化UiccStateChangedLauncher

        mCardStrings = loadCardStrings(); //加載保存在SharedPreferences中的ICCID(如果是eSIM,保存的就是EID)

        mDefaultEuiccCardId = UNINITIALIZED_CARD_ID; //初始化默認EuiccCardId

        mEuiccSlots = mContext.getResources()

                .getIntArray(com.android.internal.R.array.non_removable_euicc_slots); //獲取配置的EuiccSlot數(shù)組

        mHasBuiltInEuicc = hasBuiltInEuicc(); //如果mEuiccSlots數(shù)組不為空且長度大于0诗祸,該值為true

        PhoneConfigurationManager.registerForMultiSimConfigChange(

                this, EVENT_MULTI_SIM_CONFIG_CHANGED, null); //注冊EVENT_MULTI_SIM_CONFIG_CHANGED事件監(jiān)聽

        mPinStorage = new PinStorage(mContext);//初始化PinStorage

    }

UiccController本身是繼承了Handler的跑芳,從UiccController的構造函數(shù)可以看出來,在初始化時主要做的事件就是注冊各種SIM相關的事件監(jiān)聽和Radio狀態(tài)監(jiān)聽贬媒,確定UiccSlot的數(shù)量聋亡。

2.SIM卡的初始化時序圖

接下來看看SIM卡初始化的時序圖:

image.png

setp 1: rild進程主動上報UNSOL_RESPONSE_RADIO_STATE_CHANGED

setp 2: RIL判斷上報的射頻狀態(tài),根據(jù)上報的狀態(tài)進行不同處理际乘,下面的方法在BaseCommands中坡倔,由RadioIndication上報后調(diào)用該方法:

    //***** Protected Methods

    /**

     * Store new RadioState and send notification based on the changes

     *

     * This function is called only by RIL.java when receiving unsolicited

     * RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED

     *

     * RadioState has 3 values : RADIO_OFF, RADIO_UNAVAILABLE, RADIO_ON.

     *

     * @param newState new RadioState decoded from RIL_UNSOL_RADIO_STATE_CHANGED

     * @param forceNotifyRegistrants boolean indicating if registrants should be notified even if

     * there is no change in state

     */

    protected void setRadioState(int newState, boolean forceNotifyRegistrants) {

        int oldState;

        synchronized (mStateMonitor) {

            oldState = mState;

            mState = newState;

            if (oldState == mState && !forceNotifyRegistrants) {

                // no state transition

                return;

            }

            mRadioStateChangedRegistrants.notifyRegistrants();

            if (mState != TelephonyManager.RADIO_POWER_UNAVAILABLE

                    && oldState == TelephonyManager.RADIO_POWER_UNAVAILABLE) {

                mAvailRegistrants.notifyRegistrants();

            }

            if (mState == TelephonyManager.RADIO_POWER_UNAVAILABLE

                    && oldState != TelephonyManager.RADIO_POWER_UNAVAILABLE) {

                mNotAvailRegistrants.notifyRegistrants();

            }

            if (mState == TelephonyManager.RADIO_POWER_ON

                    && oldState != TelephonyManager.RADIO_POWER_ON) {

                mOnRegistrants.notifyRegistrants();

            }

            if ((mState == TelephonyManager.RADIO_POWER_OFF

                    || mState == TelephonyManager.RADIO_POWER_UNAVAILABLE)

                    && (oldState == TelephonyManager.RADIO_POWER_ON)) {

                mOffOrNotAvailRegistrants.notifyRegistrants();

            }

        }

    }

setp 3-4: 通過mAvailRegistrants.notifyRegistrants()通知UiccController->handlerMessage->EVENT_RADIO_AVAILABLE:

                case EVENT_RADIO_AVAILABLE:

                case EVENT_RADIO_ON:

                    if (DBG) {

                        log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling "

                                + "getIccCardStatus");

                    }

                    mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,

                            phoneId));

                    // slot status should be the same on all RILs; request it only for phoneId 0

                    if (phoneId == 0) {

                        if (DBG) {

                            log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, "

                                    + "calling getIccSlotsStatus");

                        }

                        mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE,

                                phoneId));

                    }

                    break;

setp 5-10: 射頻狀態(tài)變?yōu)?RADIO_AVAILABLE或者RADIO_ON后,開始主動獲取SIM卡狀態(tài)相關的信息脖含,調(diào)用getIccCardStatus向rild查詢罪塔,rild轉(zhuǎn)發(fā)到modem后,返回查詢到的信息养葵,再轉(zhuǎn)發(fā)返回給UiccController:

                case EVENT_GET_ICC_STATUS_DONE:

                    if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");

                    onGetIccCardStatusDone(ar, phoneId);

                    break;

setp 11: onGetIccCardStatusDone中通過mUiccSlots[slotId].update()開始更新SIM卡信息征堪,在全部更新完成后執(zhí)行mIccChangedRegistrants.notifyRegistrants通知所有關注SIM狀態(tài)的觀察者(如CatService、CarrierResolver关拒、ServiceStateTracker佃蚜、GsmSMSDispatcher、Phone等等):

    private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {

...

        IccCardStatus status = (IccCardStatus)ar.result;

...

        if (mUiccSlots[slotId] == null) {

            if (VDBG) {

                log("Creating mUiccSlots[" + slotId + "]; mUiccSlots.length = "

                        + mUiccSlots.length);

            }

            mUiccSlots[slotId] = new UiccSlot(mContext, true);

        }

        mUiccSlots[slotId].update(mCis[index], status, index, slotId);

        UiccCard card = mUiccSlots[slotId].getUiccCard();

        if (card == null) {

            if (DBG) log("mUiccSlots[" + slotId + "] has no card. Notifying IccChangedRegistrants");

            mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));

            return;

        }

...

        if (DBG) log("Notifying IccChangedRegistrants");

        mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));

    }

setp 12-13: UiccSlot更新radioState着绊,初始化UiccCard或者是EUiccCard:

    public void update(CommandsInterface ci, IccCardStatus ics, int phoneId, int slotIndex) {

        if (DBG) log("cardStatus update: " + ics.toString());

        synchronized (mLock) {

            CardState oldState = mCardState;

            mCardState = ics.mCardState;

            mIccId = ics.iccid;

            mPhoneId = phoneId;

            parseAtr(ics.atr);

            mCi = ci;

            mIsRemovable = isSlotRemovable(slotIndex);

            int radioState = mCi.getRadioState();

            if (DBG) {

                log("update: radioState=" + radioState + " mLastRadioState=" + mLastRadioState);

            }

            if (absentStateUpdateNeeded(oldState)) {

                updateCardStateAbsent();

            // Because mUiccCard may be updated in both IccCardStatus and IccSlotStatus, we need to

            // create a new UiccCard instance in two scenarios:

            //   1\. mCardState is changing from ABSENT to non ABSENT.

            //   2\. The latest mCardState is not ABSENT, but there is no UiccCard instance.

            } else if ((oldState == null || oldState == CardState.CARDSTATE_ABSENT

                    || mUiccCard == null) && mCardState != CardState.CARDSTATE_ABSENT) {

                // No notification while we are just powering up

                if (radioState != TelephonyManager.RADIO_POWER_UNAVAILABLE

                        && mLastRadioState != TelephonyManager.RADIO_POWER_UNAVAILABLE) {

                    if (DBG) log("update: notify card added");

                    sendMessage(obtainMessage(EVENT_CARD_ADDED, null));

                }

                // card is present in the slot now; create new mUiccCard

                if (mUiccCard != null) {

                    loge("update: mUiccCard != null when card was present; disposing it now");

                    mUiccCard.dispose();

                }

                if (!mIsEuicc) {

                    mUiccCard = new UiccCard(mContext, mCi, ics, mPhoneId, mLock);

                } else {

                    // The EID should be reported with the card status, but in case it's not we want

                    // to catch that here

                    if (TextUtils.isEmpty(ics.eid)) {

                        loge("update: eid is missing. ics.eid=" + ics.eid);

                    }

                    mUiccCard = new EuiccCard(mContext, mCi, ics, phoneId, mLock);

                }

            } else {

                if (mUiccCard != null) {

                    mUiccCard.update(mContext, mCi, ics);

                }

            }

            mLastRadioState = radioState;

        }

    }

setp 14-15: UiccCard更新狀態(tài)和內(nèi)容谐算,同時開始初始化UiccProfile進行更新:

    public void update(Context c, CommandsInterface ci, IccCardStatus ics) {

        synchronized (mLock) {

            mCardState = ics.mCardState;

            mContext = c;

            mCi = ci;

            mIccid = ics.iccid;

            updateCardId();

            if (mCardState != CardState.CARDSTATE_ABSENT) {

                if (mUiccProfile == null) {

                    mUiccProfile = TelephonyComponentFactory.getInstance()

                            .inject(UiccProfile.class.getName()).makeUiccProfile(

                            mContext, mCi, ics, mPhoneId, this, mLock);

                } else {

                    mUiccProfile.update(mContext, mCi, ics);

                }

            } else {

                throw new RuntimeException("Card state is absent when updating!");

            }

        }

    }

setp 16-36:初始化UiccProfile,設置PhoneType归露,調(diào)用update()初始化UiccCardApplication洲脂,UiccCardApplication初始化主要做的就是查詢當前SIM卡Fdn和Pin鎖狀態(tài),然后初始化mIccLockEnabled值狀態(tài)剧包。

UiccProfile的update()里面還做了很多事情恐锦,比如創(chuàng)建CatService往果,CatService通知StkApp進行SIM卡相關的狀態(tài)更新等等,這里就不詳細講解了一铅。

最后調(diào)用updateIccAvailability(true) > setExternalState(IccCardConstants.State.READY) > UiccController.updateInternalIccState()最終調(diào)用到了SubscriptionInfoUpdater中陕贮。

    public UiccProfile(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId,

            UiccCard uiccCard, Object lock) {

        if (DBG) log("Creating profile");

        mLock = lock;

        mUiccCard = uiccCard;

        mPhoneId = phoneId;

        if (mUiccCard instanceof EuiccCard) {

            // for RadioConfig<1.2 eid is not known when the EuiccCard is constructed

            ((EuiccCard) mUiccCard).registerForEidReady(mHandler, EVENT_EID_READY, null);

        }

        mPinStorage = UiccController.getInstance().getPinStorage();

        update(c, ci, ics);

        ci.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);

        Phone phone = PhoneFactory.getPhone(phoneId);

        if (phone != null) {

            setCurrentAppType(phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM);

        }

        resetProperties();

        updateIccAvailability(false);

        IntentFilter intentfilter = new IntentFilter();

        intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);

        c.registerReceiver(mCarrierConfigChangedReceiver, intentfilter);

    }

    /**

     * Update the UiccProfile.

     */

    public void update(Context c, CommandsInterface ci, IccCardStatus ics) {

        synchronized (mLock) {

            mUniversalPinState = ics.mUniversalPinState;

            mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;

            mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;

            mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;

            mApplicationCount = ics.mApplications.length;

            mContext = c;

            mCi = ci;

            mTelephonyManager = (TelephonyManager) mContext.getSystemService(

                    Context.TELEPHONY_SERVICE);

            //update applications

            if (DBG) log(ics.mApplications.length + " applications");

            mLastReportedNumOfUiccApplications = ics.mApplications.length;

            for (int i = 0; i < mUiccApplications.length; i++) {

                if (mUiccApplications[i] == null) {

                    //Create newly added Applications

                    if (i < ics.mApplications.length) {

                        mUiccApplications[i] = new UiccCardApplication(this,

                                ics.mApplications[i], mContext, mCi);

                    }

                } else if (i >= ics.mApplications.length) {

                    //Delete removed applications

                    mUiccApplications[i].dispose();

                    mUiccApplications[i] = null;

                } else {

                    //Update the rest

                    mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);

                }

            }

            createAndUpdateCatServiceLocked();

            // Reload the carrier privilege rules if necessary.

            log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + ics.mCardState);

            if (mCarrierPrivilegeRules == null && ics.mCardState == CardState.CARDSTATE_PRESENT) {

                mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this,

                        mHandler.obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED));

            } else if (mCarrierPrivilegeRules != null

                    && ics.mCardState != CardState.CARDSTATE_PRESENT) {

                mCarrierPrivilegeRules = null;

                mContext.getContentResolver().unregisterContentObserver(

                        mProvisionCompleteContentObserver);

            }

            sanitizeApplicationIndexesLocked();

            if (mRadioTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {

                setCurrentAppType(ServiceState.isGsm(mRadioTech));

            }

            updateIccAvailability(true);

        }

    }

    private void setExternalState(IccCardConstants.State newState, boolean override) {

        synchronized (mLock) {

            if (!SubscriptionManager.isValidSlotIndex(mPhoneId)) {

                loge("setExternalState: mPhoneId=" + mPhoneId + " is invalid; Return!!");

                return;

            }

            if (!override && newState == mExternalState) {

                log("setExternalState: !override and newstate unchanged from " + newState);

                return;

            }

            mExternalState = newState;

            if (mExternalState == IccCardConstants.State.LOADED) {

                // Update the MCC/MNC.

                if (mIccRecords != null) {

                    Phone currentPhone = PhoneFactory.getPhone(mPhoneId);

                    String operator = currentPhone.getOperatorNumeric();

                    log("setExternalState: operator=" + operator + " mPhoneId=" + mPhoneId);

                    if (!TextUtils.isEmpty(operator)) {

                        mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, operator);

                        String countryCode = operator.substring(0, 3);

                        if (countryCode != null) {

                            mTelephonyManager.setSimCountryIsoForPhone(mPhoneId,

                                    MccTable.countryCodeForMcc(countryCode));

                        } else {

                            loge("setExternalState: state LOADED; Country code is null");

                        }

                    } else {

                        loge("setExternalState: state LOADED; Operator name is null");

                    }

                }

            }

            log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);

            UiccController.updateInternalIccState(mContext, mExternalState,

                    getIccStateReason(mExternalState), mPhoneId);

        }

    }

setp 37-40: SubscriptionInfoUpdater調(diào)用sendMessage(EVENT_SIM_READY),然后執(zhí)行handleSimReady()方法開始更新SubscriptionInfo并通過SubscriptionController.notifySubscriptionInfoChanged()通知出去馅闽,并且對外發(fā)送SIM卡相關的廣播飘蚯。

    protected void handleSimReady(int phoneId) {

        List<Integer> cardIds = new ArrayList<>();

        logd("handleSimReady: phoneId: " + phoneId);

        if (sIccId[phoneId] != null && sIccId[phoneId].equals(ICCID_STRING_FOR_NO_SIM)) {

            logd(" SIM" + (phoneId + 1) + " hot plug in");

            sIccId[phoneId] = null;

        }

        // ICCID is not available in IccRecords by the time SIM Ready event received

        // hence get ICCID from UiccSlot.

        UiccSlot uiccSlot = UiccController.getInstance().getUiccSlotForPhone(phoneId);

        String iccId = (uiccSlot != null) ? IccUtils.stripTrailingFs(uiccSlot.getIccId()) : null;

        if (!TextUtils.isEmpty(iccId)) {

            sIccId[phoneId] = iccId;

            updateSubscriptionInfoByIccId(phoneId, true /* updateEmbeddedSubs */);

        }

        cardIds.add(getCardIdFromPhoneId(phoneId));

        updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {

            if (hasChanges) {

                mSubscriptionController.notifySubscriptionInfoChanged();

            }

        });

        broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_READY, null);

        broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_PRESENT);

        broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_NOT_READY);

    }

至此SIM卡初始化相關的流程差不多就結束了,其實還有一些流程和狀態(tài)變化沒有詳細說出來福也,比如IccFileHandler執(zhí)行讀取SIM卡內(nèi)容填充IccRecords、更新各種狀態(tài)相關并通知出去等等攀圈,關注這個的可以重點查看CarrierResolver暴凑、ServiceStateTracker、GsmSMSDispatcher赘来、Phone這些類的流程现喳。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市犬辰,隨后出現(xiàn)的幾起案子嗦篱,更是在濱河造成了極大的恐慌,老刑警劉巖幌缝,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灸促,死亡現(xiàn)場離奇詭異,居然都是意外死亡涵卵,警方通過查閱死者的電腦和手機浴栽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來轿偎,“玉大人典鸡,你說我怎么就攤上這事』祷蓿” “怎么了萝玷?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長昆婿。 經(jīng)常有香客問我球碉,道長,這世上最難降的妖魔是什么挖诸? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任汁尺,我火速辦了婚禮,結果婚禮上多律,老公的妹妹穿的比我還像新娘痴突。我一直安慰自己搂蜓,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布辽装。 她就那樣靜靜地躺著帮碰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拾积。 梳的紋絲不亂的頭發(fā)上殉挽,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音拓巧,去河邊找鬼斯碌。 笑死,一個胖子當著我的面吹牛肛度,可吹牛的內(nèi)容都是我干的傻唾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼承耿,長吁一口氣:“原來是場噩夢啊……” “哼冠骄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起加袋,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤凛辣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后职烧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扁誓,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年阳堕,在試婚紗的時候發(fā)現(xiàn)自己被綠了跋理。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恬总,死狀恐怖前普,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情壹堰,我是刑警寧澤拭卿,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站贱纠,受9級特大地震影響峻厚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谆焊,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一惠桃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦辜王、人聲如沸劈狐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肥缔。三九已至,卻和暖如春汹来,著一層夾襖步出監(jiān)牢的瞬間续膳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工收班, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坟岔,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓闺阱,卻偏偏與公主長得像炮车,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子酣溃,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

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