Android蓝牙协议-蓝牙打开 enable

APP/JAVA 层

蓝牙开启位于setting中,即 package:com.android.settings.bluetooth
BluetoothSettings.java 中。
蓝牙开关操作封装在BluetoothEnabler.java中,BluetoothEnabler便于蓝牙开关管理。
里面实现SwitchBar.OnSwitchChangeListener接口,监听状态改变

@Override
    public void onSwitchChanged(Switch switchView, boolean isChecked) {
          ...........
        //在LocalBluetoothAdapter中打开蓝牙
        if (mLocalAdapter != null) {
            mLocalAdapter.setBluetoothEnabled(isChecked);
        }
        mSwitch.setEnabled(false);
    }

LocalBluetoothAdapter.setBluetoothEnabled

onSwitchChanged里面调用LocalBluetoothAdapter的setBluetoothEnabled方法

    public void setBluetoothEnabled(boolean enabled) {
        boolean success = enabled
                ? mAdapter.enable()
                : mAdapter.disable();

           ......设置蓝牙状态.....
        }
    }

setBluetoothEnabled调用BluetoothAdapter.enable方法,

BluetoothAdapter.enable

 public boolean enable() {
        int state = STATE_OFF;
        //已经打开返回
        if (isEnabled() == true){
            if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
            return true;
        }
        //Use service interface to get the exact state
        if (mService != null) {
            try {
               state = mService.getState();
            } catch (RemoteException e) {Log.e(TAG, "", e);}
        }
        //当前状态为打开
        if (state == BluetoothAdapter.STATE_BLE_ON) {
                Log.e(TAG, "BT is in BLE_ON State");
                notifyUserAction(true);
                return true;
        }
        try {
            //通过远程服务打开蓝牙
            return mManagerService.enable();
        } catch (RemoteException e) {Log.e(TAG, "", e);}
        return false;
    }

enabled打来蓝牙时会先检查当前蓝牙状态,如果已经enbale直接返回,如果没有通过远程服务查询当前状态,如果是打开状态直接返回,经过以上检查没有满足,调用IBluetoothManager.enable方法,开启蓝牙。

IBluetoothManager.enable

IBluetoothManager实际定义的是AIDL 文件,具体的实现位于com.android.server包下的BluetoothManagerService.java文件

public boolean enable() {
        //当前用户和系统用户,6.0多用户相关检查
        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
            (!checkIfCallerIsForegroundUser())) {
            Log.w(TAG,"enable(): not allowed for non-active and non system user");
            return false;
        }

        //权限检查
        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                "Need BLUETOOTH ADMIN permission");
        if (DBG) {
            Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +
                    " mBinding = " + mBinding);
        }

        synchronized(mReceiver) {
            mQuietEnableExternal = false;
            mEnableExternal = true;
            // waive WRITE_SECURE_SETTINGS permission check
            //通过handler集中处理消息
            sendEnableMsg(false);
        }
        if (DBG) Log.d(TAG, "enable returning");
        return true;
    }

handler最后调用handleEnable方法处理该消息

BluetoothManagerService.handleEnable

handleEnable会检查是否绑定了IBluetooth Server,如果没有绑定已经绑定调用IBluetooth.enable方法打开蓝牙

    private void handleEnable(boolean quietMode) {
        mQuietEnable = quietMode;

        synchronized(mConnection) {
            //检查服务是否已经启动并且已经绑定
            if ((mBluetooth == null) && (!mBinding)) {
                //Start bind timeout and bind
                Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
                mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
                mConnection.setGetNameAddressOnly(false);
                Intent i = new Intent(IBluetooth.class.getName());
                //绑定服务,UserHandle为多用户考虑
                if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
                        UserHandle.CURRENT)) {
                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
                } else {
                    mBinding = true;
                }
            } else if (mBluetooth != null) {
                if (mConnection.isGetNameAddressOnly()) {
                    // if GetNameAddressOnly is set, we can clear this flag,
                    // so the service won't be unbind
                    // after name and address are saved
                    mConnection.setGetNameAddressOnly(false);
                    //Register callback object
                    try {
                        mBluetooth.registerCallback(mBluetoothCallback);
                    } catch (RemoteException re) {
                        Log.e(TAG, "Unable to register BluetoothCallback",re);
                    }
                    //Inform BluetoothAdapter instances that service is up
                    sendBluetoothServiceUpCallback();
                }

                //Enable bluetooth
                try {
                    if (!mQuietEnable) {
                        //使能蓝牙
                        if(!mBluetooth.enable()) {
                            Log.e(TAG,"IBluetooth.enable() returned false");
                        }
                    }
                    else {
                        if(!mBluetooth.enableNoAutoConnect()) {
                            Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
                        }
                    }
                } catch (RemoteException e) {
                    Log.e(TAG,"Unable to call enable()",e);
                }
            }
        }
    }

服务没有绑定使用bind绑定服务 Intent i = new Intent(IBluetooth.class.getName());服务绑定时,会发送Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
handler处理MESSAGE_BLUETOOTH_SERVICE_CONNECTED消息时,会做一下事情

  • 赋值server
    IBluetooth 赋值
  • 注册IBluetooth回调函数
    mBluetooth.registerCallback(mBluetoothCallback);
  • 调用enable方法方法开启蓝牙

IBluetooth.enable -->AdapterServiceBinder.enable

IBluetooth也是定义AIDL接口,具体实现是位于com.android.bluetooth.btservice包下的AdapterServiceBinder。
IBluetooth.enable方法会接着调用AdapterService.enable方法,最终向状态机AdapterState发送AdapterState.BLE_TURN_ON消息,由状态机处理消息

public synchronized boolean enable(boolean quietMode) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");

         debugLog("enable() - Enable called with quiet mode status =  " + mQuietmode);
         mQuietmode = quietMode;
        //由状态机处理
         Message m = mAdapterStateMachine.obtainMessage(AdapterState.BLE_TURN_ON);
         mAdapterStateMachine.sendMessage(m);
         return true;
     }

AdapterState状态机

AdapterState状态机在AdapterService的onCreate方法中他通过一个静态函数AdapterState.make初始化。

private AdapterState(AdapterService service, AdapterProperties adapterProperties) {
        super("BluetoothAdapterState:");
        addState(mOnState);
        addState(mBleOnState);
        addState(mOffState);
        addState(mPendingCommandState);
        mAdapterService = service;
        mAdapterProperties = adapterProperties;
        //初始状态为关闭
        setInitialState(mOffState);
    }

setInitialState设置了该状态机的初始状态是OffState,AdapterState.BLE_TURN_ON消息由OffState首先处理,状态机中每个状态通过调用public boolean processMessage方法处理每个消息。

        @Override
        public boolean processMessage(Message msg) {
            AdapterService adapterService = mAdapterService;
            if (adapterService == null) {
                errorLog("Received message in OffState after cleanup: " + msg.what);
                return false;
            }

            debugLog("Current state: OFF, message: " + msg.what);

            switch(msg.what) {
                //初始状态是OffState,由OffState处理蓝牙开启操作
               case BLE_TURN_ON:
                   //通知BluetoothmangerService蓝牙正在开启
                   notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON);
                   mPendingCommandState.setBleTurningOn(true);
                   transitionTo(mPendingCommandState);
                   //发送延迟消息,检测打开超时任务
                   sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
                   //批量启动 profile service
                   adapterService.BleOnProcessStart();
                   break;

               case USER_TURN_OFF:
                   //TODO: Handle case of service started and stopped without enable
                   break;

               default:
                   return false;
            }
            return true;
        }

该方法主要工作

  • 通过回调通知BluetoothMangerService,蓝牙正在启动中,
  • 将状态机中下个状态设置为PendingCommandState
  • 开启一个蓝牙开启的超时检测
  • 调用BleOnProcessStart批量启动所需的各个profile server

BleOnProcessStart

    void BleOnProcessStart() {
        debugLog("BleOnProcessStart()");
        //支持的profile service
        Class[] supportedProfileServices = Config.getSupportedProfiles();
        //Initialize data objects
        for (int i=0; i < supportedProfileServices.length;i++) {
            mProfileServicesState.put(supportedProfileServices[i].getName(),BluetoothAdapter.STATE_OFF);
        }

        //初始化远程蓝牙设备
        mRemoteDevices = new RemoteDevices(this);
        mAdapterProperties.init(mRemoteDevices);

        debugLog("BleOnProcessStart() - Make Bond State Machine");
        //启动蓝牙绑定状态状态
        mBondStateMachine = BondStateMachine.make(this, mAdapterProperties, mRemoteDevices);

        mJniCallbacks.init(mBondStateMachine,mRemoteDevices);

        //FIXME: Set static instance here???
        setAdapterService(this);

        //Start Gatt service
        setGattProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);
    }

BleOnProcessStart首先获取支持的profile,支持的profile在 Config.java 中

    /**
     * List of profile services.
     */
    @SuppressWarnings("rawtypes")
    //Do not inclue OPP and PBAP, because their services
    //are not managed by AdapterService
    private static final Class[] PROFILE_SERVICES = {
        HeadsetService.class,
        A2dpService.class,
        A2dpSinkService.class,
        HidService.class,
        HealthService.class,
        PanService.class,
        GattService.class,
        BluetoothMapService.class,
        HeadsetClientService.class,
        AvrcpControllerService.class,
        SapService.class
    };

接着还会启动新的状态机BondStateMachine,
调用setGattProfileServiceState方法,批量启动Peofile server,启动的服务里会传入intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);ACTION_SERVICE_STATE_CHANGED会在后面使用

到这里还是没有发现在哪里启动蓝牙,其实蓝牙的启动在刚才批量启动的一个服务里。即GattService.java

GattService

在onStartCommand里面没有做什么,看父类实现

    public int onStartCommand(Intent intent, int flags, int startId) {
        if (DBG) log("onStartCommand()");
        if (mStartError || mAdapter == null) {
            Log.w(mName, "Stopping profile service: device does not have BT");
            doStop(intent);
            return PROFILE_SERVICE_MODE;
        }

        if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) {
            Log.e(mName, "Permission denied!");
            return PROFILE_SERVICE_MODE;
        }

        if (intent == null) {
            Log.d(mName, "Restarting profile service...");
            return PROFILE_SERVICE_MODE;
        } else {
            String action = intent.getStringExtra(AdapterService.EXTRA_ACTION);
            if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
                int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
                if(state==BluetoothAdapter.STATE_OFF) {
                    Log.d(mName, "Received stop request...Stopping profile...");
                    doStop(intent);
                } else if (state == BluetoothAdapter.STATE_ON) {
                    Log.d(mName, "Received start request. Starting profile...");
                    //启动
                    doStart(intent);
                }
            }
        }
        return PROFILE_SERVICE_MODE;
    }

调用doStart方法,doStart再调用start方法,start是个抽象方法,子类实现该方法做相应的预处理。
调用notifyProfileServiceStateChanged(BluetoothAdapter.STATE_ON);通知蓝牙开启,notifyProfileServiceStateChanged调用AdapterService.onProfileServiceStateChanged方法,传递STATE_ON消息,该消息会包装在MESSAGE_PROFILE_SERVICE_STATE_CHANGED类型里,由AdapterService的handler方法处理,

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            debugLog("handleMessage() - Message: " + msg.what);

            switch (msg.what) {
                case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: {
                    debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_STATE_CHANGED");
                    processProfileServiceStateChanged((String) msg.obj, msg.arg1);
                }
                 ..............省略.......................
            }
        }
    };

processProfileServiceStateChanged处理profile 状态改变,其中

//在OffState中,isBleTurningOn设置为true
        if (isBleTurningOn) {
            if (serviceName.equals("com.android.bluetooth.gatt.GattService")) {
                debugLog("GattService is started");
                mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BLE_STARTED));
                return;
            }

        }

会向AdapterStateMachine状态机发送BLE_STARTED消息,根据之前状态机的改变,该消息由PendingCommandState状态处理,看processMessage的处理

                case BLE_STARTED:
                    //Remove start timeout
                    removeMessages(BLE_START_TIMEOUT);

                    //Enable,调用底层方法,开启蓝牙
                    if (!adapterService.enableNative()) {
                        errorLog("Error while turning Bluetooth on");
                        //开启失败,状态通知,切换到OffState状态
                        notifyAdapterStateChange(BluetoothAdapter.STATE_OFF);
                        transitionTo(mOffState);
                    } else {
                        //超时检测
                        sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY);
                    }
                    break;

通过调用adapterService.enableNative()方法,开始调用JNI方法,进入C/C++层,到此java层调用至此。

休息一下

JNI

adapterService.enableNative 具体位置位于
packages/apps/Bluetooth/jni目录下,对应的cpp文件为com_android_bluetooth_btservice_AdapterService.cpp

cpp 文件和源java文件命名类似,将对应的包名的.改为_;文件的java源文件命名cpp文件

enableNative

//蓝牙使能
static jboolean enableNative(JNIEnv* env, jobject obj) {
    ALOGV("%s:",__FUNCTION__);

    jboolean result = JNI_FALSE;
    if (!sBluetoothInterface) return result;

    int ret = sBluetoothInterface->enable();
    result = (ret == BT_STATUS_SUCCESS || ret == BT_STATUS_DONE) ? JNI_TRUE : JNI_FALSE;
    return result;
}

static int enable(void) {
  LOG_INFO("%s", __func__);
  
  //状态判断
  if (!interface_ready())
    return BT_STATUS_NOT_READY;

  stack_manager_get_interface()->start_up_stack_async();
  return BT_STATUS_SUCCESS;
}

enableNative 调用sBluetoothInterface的enable方法,enable方法会调用start_up_stack_async方法。直接看看start_up_stack_async如何启动。

start_up_stack_async的实现在stack_manager.c 文件中,通过thread_post异步event_start_up_stack,来启动蓝牙栈,

event_start_up_stack

//启动蓝牙栈
// Synchronous function to start up the stack
static void event_start_up_stack(UNUSED_ATTR void *context) {
  if (stack_is_running) {
    LOG_DEBUG("%s stack already brought up.", __func__);
    return;
  }

  ensure_stack_is_initialized();

  LOG_DEBUG("%s is bringing up the stack.", __func__);
  hack_future = future_new();

  // Include this for now to put btif config into a shutdown-able state
  //加载配置文件,配置文件位于手机系统目录/data/misc/bluedroid/bt_config.xml
  module_start_up(get_module(BTIF_CONFIG_MODULE));
  //ble enable
  bte_main_enable();

  //启动失败
  if (future_await(hack_future) != FUTURE_SUCCESS) {
    stack_is_running = true; // So stack shutdown actually happens
    //关闭蓝牙栈,里面还会调用
    event_shut_down_stack(NULL);
    return;
  }

  stack_is_running = true;
  LOG_DEBUG("%s finished", __func__);
  //发送蓝牙栈启动信息,适配已经打开
  btif_thread_post(event_signal_stack_up, NULL);
}

event_start_up_stack工作

  • 调用ensure_stack_is_initialized确保,栈已经初始化,如果没有,则进行初始化。

    初始化内容表多,暂不分析

  • 调用module_start_up加载配置文件
  • 调用bte_main_enable启动蓝牙

    内容比较多,暂不分析

  • 如果成功调用event_signal_stack_up方法,event_signal_stack_up方法调用 HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_ON);通过回调调用adapter_state_changed_cb方法,回调java层方法,通知蓝牙当前状态BT_STATE_ON
  • 如果失败调用event_shut_down_stack方法,里面调用event_signal_stack_down,最终调用HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF);方法,回调java层方法,通知蓝牙当前状态为BT_STATE_OFF

adapter_state_changed_cb 回调方法

adapter_state_changed_cb 定义在哪以及如何建立java层到C++层的关系

adapter_state_changed_cb 的在bluetooth.h 文件中

/** Bluetooth DM callback structure. */
typedef struct {
    /** set to sizeof(bt_callbacks_t) */
    size_t size;
    adapter_state_changed_callback adapter_state_changed_cb;
    adapter_properties_callback adapter_properties_cb;
    remote_device_properties_callback remote_device_properties_cb;
    device_found_callback device_found_cb;
    discovery_state_changed_callback discovery_state_changed_cb;
    pin_request_callback pin_request_cb;
    ssp_request_callback ssp_request_cb;
    bond_state_changed_callback bond_state_changed_cb;
    acl_state_changed_callback acl_state_changed_cb;
    callback_thread_event thread_evt_cb;
    dut_mode_recv_callback dut_mode_recv_cb;
    le_test_mode_callback le_test_mode_cb;
    energy_info_callback energy_info_cb;
} bt_callbacks_t;

bt_callbacks_t 定义了java层的回调接口,如果C++层有消息传递到java层,回调接口都定义在这里。将接口更换名称adapter_state_changed_callback -->adapter_state_changed_cb;调用adapter_state_changed_cb即调用adapter_state_changed_callback。

首先这些回调接口定义在java文件中,即AdapterService.java;
AdapterService.java中有静态native方法,classInitNative,看C++做那些

static void classInitNative(JNIEnv* env, jclass clazz) {
    int err;
    hw_module_t* module;

    jclass jniCallbackClass =
        env->FindClass("com/android/bluetooth/btservice/JniCallbacks");
    sJniCallbacksField = env->GetFieldID(clazz, "mJniCallbacks",
        "Lcom/android/bluetooth/btservice/JniCallbacks;");

    method_stateChangeCallback = env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V");

    method_adapterPropertyChangedCallback = env->GetMethodID(jniCallbackClass,
                                                             "adapterPropertyChangedCallback",
                                                             "([I[[B)V");
    method_discoveryStateChangeCallback = env->GetMethodID(jniCallbackClass,
                                                           "discoveryStateChangeCallback", "(I)V");
    ........................省略..............................
}

该方法主要是将位于JniCallbacks.java定义的回调方法映射到对应的C++层方法,如method_stateChangeCallback 对应方法stateChangeCallback的id。

通过 initNative方法来初始化方法变量

static bool initNative(JNIEnv* env, jobject obj) {
    ALOGV("%s:",__FUNCTION__);

    sJniAdapterServiceObj = env->NewGlobalRef(obj);
    sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField));

    if (sBluetoothInterface) {
        int ret = sBluetoothInterface->init(&sBluetoothCallbacks);
        if (ret != BT_STATUS_SUCCESS) {
            ALOGE("Error while setting the callbacks: %d\n", ret);
            sBluetoothInterface = NULL;
            return JNI_FALSE;
        }
        ret = sBluetoothInterface->set_os_callouts(&sBluetoothOsCallouts);
        if (ret != BT_STATUS_SUCCESS) {
            ALOGE("Error while setting Bluetooth callouts: %d\n", ret);
            sBluetoothInterface->cleanup();
            sBluetoothInterface = NULL;
            return JNI_FALSE;
        }

        if ( (sBluetoothSocketInterface = (btsock_interface_t *)
                  sBluetoothInterface->get_profile_interface(BT_PROFILE_SOCKETS_ID)) == NULL) {
                ALOGE("Error getting socket interface");
        }

        return JNI_TRUE;
    }
    return JNI_FALSE;
}

主要是将 sBluetoothCallbacks设置在sBluetoothInterface中。

余下便是JNI初始化
JNI_OnLoad,调用register_com_android_bluetooth_btservice_AdapterService注册使用的方法。这些方法存放在数组中

static JNINativeMethod sMethods[] = {
    /* name, signature, funcPtr */
    {"classInitNative", "()V", (void *) classInitNative},
    {"initNative", "()Z", (void *) initNative},
    {"cleanupNative", "()V", (void*) cleanupNative},
    {"enableNative", "()Z",  (void*) enableNative},
    {"disableNative", "()Z",  (void*) disableNative},
    {"setAdapterPropertyNative", "(I[B)Z", (void*) setAdapterPropertyNative},
    {"getAdapterPropertiesNative", "()Z", (void*) getAdapterPropertiesNative},
    {"getAdapterPropertyNative", "(I)Z", (void*) getAdapterPropertyNative},
    {"getDevicePropertyNative", "([BI)Z", (void*) getDevicePropertyNative},
    {"setDevicePropertyNative", "([BI[B)Z", (void*) setDevicePropertyNative},
    {"startDiscoveryNative", "()Z", (void*) startDiscoveryNative},
    {"cancelDiscoveryNative", "()Z", (void*) cancelDiscoveryNative},
    {"createBondNative", "([BI)Z", (void*) createBondNative},
    {"removeBondNative", "([B)Z", (void*) removeBondNative},
    {"cancelBondNative", "([B)Z", (void*) cancelBondNative},
    {"getConnectionStateNative", "([B)I", (void*) getConnectionStateNative},
    {"pinReplyNative", "([BZI[B)Z", (void*) pinReplyNative},
    {"sspReplyNative", "([BIZI)Z", (void*) sspReplyNative},
    {"getRemoteServicesNative", "([B)Z", (void*) getRemoteServicesNative},
    {"connectSocketNative", "([BI[BII)I", (void*) connectSocketNative},
    {"createSocketChannelNative", "(ILjava/lang/String;[BII)I",
     (void*) createSocketChannelNative},
    {"configHciSnoopLogNative", "(Z)Z", (void*) configHciSnoopLogNative},
    {"alarmFiredNative", "()V", (void *) alarmFiredNative},
    {"readEnergyInfo", "()I", (void*) readEnergyInfo},
    {"dumpNative", "(Ljava/io/FileDescriptor;)V", (void*) dumpNative},
    {"factoryResetNative", "()Z", (void*)factoryResetNative}
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容