Android 蓝牙enable()方法分析

在权限允许的情况下,通过enable()函数可以打开Android设备的本地蓝牙。调用该函数需要权限Manifest.permission.BLUETOOTH_ADMIN。它是BluetoothAdapter的函数,那就先从这开始分析:

 private final IBluetoothManager mManagerService;

 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
 public boolean enable() { 
    if (isEnabled()) {
        // 蓝牙已经可用,直接返回true
        return true;
    }
    try {
        return mManagerService.enable(ActivityThread.currentPackageName());
    } catch (RemoteException e) {Log.e(TAG, "", e);}
    return false;
 }

BluetoothAdapterenable()函数很简单,通过aidl的方式,调用远程服务BluetoothManagerServiceenable(packageName)函数:

public boolean enable(String packageName) throws RemoteException {
    final int callingUid = Binder.getCallingUid();
    final boolean callerSystem = UserHandle.getAppId(callingUid) ==Process.SYSTEM_UID;

    // 如果蓝牙被禁用,直接返回false
    if (isBluetoothDisallowed()) {
        return false;
    }

    if (!callerSystem) {
        if (!checkIfCallerIsForegroundUser()) {
                return false;
        }

        // 检测是否拥有BLUETOOTH_ADMIN权限
        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,"Need BLUETOOTH ADMIN permission");

        if (!isEnabled() && mPermissionReviewRequired
                && startConsentUiIfNeeded(packageName, callingUid,
                        BluetoothAdapter.ACTION_REQUEST_ENABLE)) {
            return false;
        }
    }
    synchronized(mReceiver) {
        mQuietEnableExternal = false;
        mEnableExternal = true;
        // 通过BluetoothHandler去处理enable的消息
        sendEnableMsg(false, packageName);
    }
    return true;
}

在函数中先是检查各种权限,权限都通过之后,向BluetoothHandler发送消息,交给它去完成接下来的开启任务,到这意味着开启任务已经开始,该函数的任务已经结束返回true。因此这里返回true并不代表蓝牙功能开启成功,仅仅表示这项工作通过了层层检测,步上了正轨。继续看sendEnableMsg()函数

private void sendEnableMsg(boolean quietMode, String packageName) {
    mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
                             quietMode ? 1 : 0, 0));
}

接着看BluetoothHandlerhandleMessage()函数,这个函数很长,有450行代码,这里只看MESSAGE_ENABLE分支:

private IBluetooth mBluetooth;

public void handleMessage(Message msg) {
    switch (msg.what) {
        case MESSAGE_ENABLE:
            mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
            mEnable = true;
            try {
                // 通过读写锁来保证线程安全
                mBluetoothLock.readLock().lock();
                if (mBluetooth != null) {
                    // 获取当前蓝牙状态,如果当前处于STATE_BLE_ON状态,那就切换到USER_TURN_ON状态,并返回
                    int state = mBluetooth.getState();
                    if (state == BluetoothAdapter.STATE_BLE_ON) {
                        mBluetooth.onLeServiceUp();
                        persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
                        break;
                    }
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "", e);
            } finally {
                mBluetoothLock.readLock().unlock();
            }
            mQuietEnable = (msg.arg1 == 1);
            if (mBluetooth == null) {
                // 执行enable()的函数
                handleEnable(mQuietEnable);
            } else {
                //
                // We need to wait until transitioned to STATE_OFF and
                // the previous Bluetooth process has exited. The
                // waiting period has three components:
                // (a) Wait until the local state is STATE_OFF. This
                //     is accomplished by "waitForOnOff(false, true)".
                // (b) Wait until the STATE_OFF state is updated to
                //     all components.
                // (c) Wait until the Bluetooth process exits, and
                //     ActivityManager detects it.
                // The waiting for (b) and (c) is accomplished by
                // delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE
                // message. On slower devices, that delay needs to be
                // on the order of (2 * SERVICE_RESTART_TIME_MS).
                //

                // 远程服务已连接,并且当前不是STATE_BLE_ON状态,那么需要重启蓝牙服务。
                // 需要等待本地蓝牙功能关闭,然后重启蓝牙服务
                waitForOnOff(false, true);
                Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
            }
            break;

}

重点看handleEnable(bool)函数:

private void handleEnable(boolean quietMode) {
    mQuietEnable = quietMode;
    try {
        mBluetoothLock.writeLock().lock();
        if ((mBluetooth == null) && (!mBinding)) {
            // 没有绑定服务,发起服务绑定,并设置绑定超时时间为3s
            Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
            mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
            Intent i = new Intent(IBluetooth.class.getName());
            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) {
            try {
                if (!mQuietEnable) {
                    // 调用enable函数,开启蓝牙
                    if(!mBluetooth.enable()) {
                        Slog.e(TAG,"IBluetooth.enable() returned false");
                    }
                }
                else {
                    if(!mBluetooth.enableNoAutoConnect()) {
                        Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
                    }
                }
             } catch (RemoteException e) {
                  Slog.e(TAG,"Unable to call enable()",e);
             }
        }
     } finally {
        mBluetoothLock.writeLock().unlock();
    }
}

核心代码就是mBluetooth.enable() ,其余的忽略。通过AIDL调用的是远程服务AdapterService中的enable()函数。
接着看AdapterService:

 private AdapterState mAdapterStateMachine;

 public boolean enable() {
    return enable(false);
 }
 public synchronized boolean enable(boolean quietMode) {
    // 检测权限 
    enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");

    if (mUserManager.hasUserRestriction(UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM)) {
        // 蓝牙不允许使用
        return false;
    }
    mQuietmode = quietMode;
    mAdapterStateMachine.sendMessage(AdapterState.BLE_TURN_ON);
    return true;
}

核心代码是mAdapterStateMachine.sendMessage(AdapterState.BLE_TURN_ON);,那么mAdapterStateMachine又是什么对象呢,从命名上可以看出它是个状态机,因此这里是往状态机AdapterState中发送了一条BLE_TURN_ON的消息。接着看状态机AdapterState

/**
* This state machine handles Bluetooth Adapter State.
* Stable States:
*      {@link OffState}: Initial State
*      {@link BleOnState} : Bluetooth Low Energy, Including GATT, is on
*      {@link OnState} : Bluetooth is on (All supported profiles)
*
* Transition States:
*      {@link TurningBleOnState} : OffState to BleOnState
*      {@link TurningBleOffState} : BleOnState to OffState
*      {@link TurningOnState} : BleOnState to OnState
*      {@link TurningOffState} : OnState to BleOnState
*
*        +------   Off  <-----+
*        |                    |
*        v                    |
* TurningBleOn   TO--->   TurningBleOff
*        |                  ^ ^
*        |                  | |
*        +----->        ----+ |
*                 BleOn       |
*        +------        <---+ O
*        v                  | T
*    TurningOn  TO---->  TurningOff
*        |                    ^
*        |                    |
*        +----->   On   ------+
*
*/
final class AdapterState extends StateMachine {

    private AdapterService mAdapterService;

    private TurningOnState mTurningOnState = new TurningOnState();
    private TurningBleOnState mTurningBleOnState = new TurningBleOnState();
    private TurningOffState mTurningOffState = new TurningOffState();
    private TurningBleOffState mTurningBleOffState = new TurningBleOffState();
    private OnState mOnState = new OnState();
    private OffState mOffState = new OffState();
    private BleOnState mBleOnState = new BleOnState();

    private AdapterState(AdapterService service) {
       super(TAG);
       addState(mOnState);
       addState(mBleOnState);
       addState(mOffState);
       addState(mTurningOnState);
       addState(mTurningOffState);
       addState(mTurningBleOnState);
       addState(mTurningBleOffState);
       mAdapterService = service;
       setInitialState(mOffState);
   }

    public static AdapterState make(AdapterService service) {   
       AdapterState as = new AdapterState(service);
       as.start();
       return as;
   }

    private class OffState extends BaseAdapterState {

      @Override
      int getStateValue() {
           return BluetoothAdapter.STATE_OFF;
       }
      @Override
      public boolean processMessage(Message msg) {
           switch (msg.what) {
                case BLE_TURN_ON:
                  transitionTo(mTurningBleOnState);
                  break;

              default:
                  return false;
          }
          return true;
      }
   }

}

从源码注释上可以清楚了解到状态机拥有的所有状态,状态机的使用以及原理之前分析过,这里再看一下:

  • addState(state),蓝牙状态机总共有7中状态,都没有父状态;
  • setInitialState(state),蓝牙初始状态是offState
  • StateprocessMessage()函数中处理消息。

AdapterService中向状态机发送了BLE_TURN_ON消息,此时状态机的状态是OffState。在OffState类的processMessage()函数中对BLE_TURN_ON消息的处理是:调用transitionTo(mTurningBleOnState),将状态切换到TurningBleOnState。那么TurningBleOnState()将会执行enter()方法,接着看看在enter()函数里做了什么事情:

  private class TurningBleOnState extends BaseAdapterState {

       @Override
       public void enter() {
           super.enter();
           sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
           mAdapterService.bringUpBle();
       }
   }

先设置了4s超时时间,然后调用AdapterServicebringUpBle()函数。

那么接着回到AdapterService类中,看一下bringUpBle()函数:

// 删减了无关代码
void bringUpBle() {     

    // 重置蓝牙设备
    mRemoteDevices.reset();
    // 初始化蓝牙相关属性
    mAdapterProperties.init(mRemoteDevices);
    // 启动蓝牙绑定状态机
    mBondStateMachine = BondStateMachine.make(this, mAdapterProperties, mRemoteDevices);
    // 初始化JNI回调类
    mJniCallbacks.init(mBondStateMachine, mRemoteDevices);
    try {
        // 标记重置蓝牙Ble扫描的电池统计
        mBatteryStats.noteResetBleScan();
    } catch (RemoteException e) {
    }
    // 启动Gatt协议服务
    setProfileServiceState(GattService.class, BluetoothAdapter.STATE_ON);
}

在这个函数里头,首先做了一系列初始化工作,然后启动Gatt协议服务,接着看setProfileServiceState()函数:

  private void setProfileServiceState(Class service, int state) {
        Intent intent = new Intent(this, service);
        intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
        startService(intent);
  }

代码很简单,就是启动GattService,告知GattService执行ACTION_SERVICE_STATE_CHANGED相关操作。

GattService父类ProfileServiceonStartCommand()函数看到了对ACTION_SERVICE_STATE_CHANGEDaction的处理:

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
    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) {
            doStop();
        } else if (state == BluetoothAdapter.STATE_ON) {
            doStart();
        }
    }
    return PROFILE_SERVICE_MODE;
}

private void doStart() {
    // 省略了其他代码
    mAdapterService.onProfileServiceStateChanged(this, BluetoothAdapter.STATE_ON);
}    

doStart()中调用start()方法启动了一系列Manager,做了一些预处理,最后调用AdapterServiceonProfileServiceStateChanged()方法。

private final AdapterServiceHandler mHandler = new AdapterServiceHandler();

public void onProfileServiceStateChanged(ProfileService profile, int state) {
    // 只处理蓝牙打开与关闭状态
    if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
        throw new IllegalArgumentException(BluetoothAdapter.nameForState(state));
    }
    Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED);
    m.obj = profile;
    m.arg1 = state;
    mHandler.sendMessage(m);
}

AdapterServiceHandler发送一条MESSAGE_PROFILE_SERVICE_STATE_CHANGED的消息,接着看AdapterServiceHandlerhandlerMessage()方法。

class AdapterServiceHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MESSAGE_PROFILE_SERVICE_STATE_CHANGED:
                processProfileServiceStateChanged((ProfileService) msg.obj, msg.arg1);
                break;
        }
    }
    private void processProfileServiceStateChanged(ProfileService profile, int state) {
        switch (state) {
            case BluetoothAdapter.STATE_ON:
                mRunningProfiles.add(profile);
                if (GattService.class.getSimpleName().equals(profile.getName())) {
                    // 
                    enableNativeWithGuestFlag();
                } else if (mRegisteredProfiles.size() == Config.getSupportedProfiles().length
                        && mRegisteredProfiles.size() == mRunningProfiles.size()) {
                    mAdapterProperties.onBluetoothReady();
                    updateUuids();
                    setBluetoothClassFromConfig();
                    mAdapterStateMachine.sendMessage(AdapterState.BREDR_STARTED);
                }
            break;
         }
       }
   }
}

这里的ProfileService指的就是GattService,因此进入enableNativeWithGuestFlag()函数:

  private void enableNativeWithGuestFlag() {
      boolean isGuest = UserManager.get(this).isGuestUser();
      if (!enableNative(isGuest)) {
          Log.e(TAG, "enableNative() returned false");
      }
  }

  native boolean enableNative(boolean startRestricted);

最终调用JNI的enableNative(),在com_android_bluetooth_btservice_AdapterService.cpp

static jboolean enableNative(JNIEnv* env, jobject obj, jboolean isGuest) { 
     ALOGV("%s", __func__);
     if (!sBluetoothInterface) return JNI_FALSE;
     int ret = sBluetoothInterface->enable(isGuest == JNI_TRUE ? 1 : 0);
     return (ret == BT_STATUS_SUCCESS || ret == BT_STATUS_DONE) ? JNI_TRUE: JNI_FALSE;
}

通过sBluetoothInterface->enable()方法去调用蓝牙的底层驱动来实现蓝牙的打开操作。那么sBluetoothInterface又是什么呢???它对应的是bluetooth.cc,在bluetooth.cc中可以看到:

EXPORT_SYMBOL bt_interface_t bluetoothInterface = {
   sizeof(bluetoothInterface),
   init,
   enable,
   disable,
   cleanup,
   get_adapter_properties,
   get_adapter_property,
   set_adapter_property,
   get_remote_device_properties,
   get_remote_device_property,
   set_remote_device_property,
   get_remote_service_record,
   get_remote_services,
   start_discovery,
   cancel_discovery,
   create_bond,
   create_bond_out_of_band,
   remove_bond,
   cancel_bond,
   get_connection_state,
   pin_reply,
   ssp_reply,
   get_profile_interface,
   dut_mode_configure,
   dut_mode_send,
   le_test_mode,
   set_os_callouts,
   read_energy_info,
   dump,
   dumpMetrics,
   config_clear,
   interop_database_clear,
   interop_database_add,
   get_avrcp_service,
};

可以理解为导出对应的内核方法供其他模块使用。回到正题,看一下enable()方法:

static int enable(bool start_restricted) {
   restricted_mode = start_restricted;
   // 接口未就绪,返回未就绪的状态码
   if (!interface_ready()) return BT_STATUS_NOT_READY;

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

接着执行stack_manager_get_interface()start_up_stack_async()stack_manager_get_interface()函数指的是stack_manager.cc,接着看:

static void start_up_stack_async(void) { 
   thread_post(management_thread, event_start_up_stack, NULL);
}

这里通过thread_post异步去执行event_start_up_stack函数:

// start_up过程是一个同步过程
static void event_start_up_stack(UNUSED_ATTR void* context) {

   // 确保栈已经初始化 
   ensure_stack_is_initialized();

   // 加载配置文件
   module_start_up(get_module(BTIF_CONFIG_MODULE));

   // 执行enable
   bte_main_enable();

   // 上一步的enable失败 
   if (future_await(local_hack_future) != FUTURE_SUCCESS) {
     stack_is_running = true;  
     event_shut_down_stack(NULL);
     return;
   }

   stack_is_running = true;
   // enable成功
   btif_thread_post(event_signal_stack_up, NULL);
}

bte_main_enable()是在bte_main.cc中执行的,具体的实现就不再深入。接下来让我们看看成功的结果是如何返回到Java层的。

bte_main_enable()执行成功之后,会在event_signal_stack_up()函数中执行回掉,将BT_STATE_ON状态通过HAL_CBACK函数回传给adapter_state_changed_cb ()函数 。

static void event_signal_stack_up(UNUSED_ATTR void* context) {
     // Notify BTIF connect queue that we've brought up the stack. It's
     // now time to dispatch all the pending profile connect requests.
     btif_queue_connect_next();
     HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_ON);
}

函数adapter_state_changed_cb()对应的是com_android_bluetooth_btservice_AdapterService.cpp中的adapter_state_change_callback()函数

static void adapter_state_change_callback(bt_state_t status) {
     CallbackEnv sCallbackEnv(__func__);
     if (!sCallbackEnv.valid()) return;
     sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback, (jint)status);
}

这里有一个疑惑,stack_manager.cc中调用的adapter_state_changed_cb()函数是如何对应到com_android_bluetooth_btservice_AdapterService.cpp中的adapter_state_change_callback()函数的????在bluetooth.h中看到了结构体bt_callbacks_t中声明:

typedef struct {
  adapter_state_changed_callback adapter_state_changed_cb;
} bt_callbacks_t;

com_android_bluetooth_btservice_AdapterService.cpp中创建了bt_callbacks_t对象。由于c/c++基础不好,所以这部分很多都是个人的猜测。

static bt_callbacks_t sBluetoothCallbacks = {
    adapter_state_change_callback
};

JNI层通过CallVoidMethod(xx, method_stateChangeCallback, BT_STATE_ON)去调用Java层AdapterService.java中的stateChangeCallback()函数:

void stateChangeCallback(int status) {
    if (status == AbstractionLayer.BT_STATE_OFF) {
        debugLog("stateChangeCallback: disableNative() completed");
    } else if (status == AbstractionLayer.BT_STATE_ON) {
        // 
        mAdapterStateMachine.sendMessage(AdapterState.BLE_STARTED);
    } else {
           Log.e(TAG, "Incorrect status " + status + " in stateChangeCallback");
    }
}

返回的状态是BT_STATE_ON,所以接着给状态机AdapterState发送消息BLE_STARTED

private class TurningBleOnState extends BaseAdapterState {

       @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
              case BLE_STARTED:
                 transitionTo(mBleOnState);
                  break;
            }
            return true;
       }
}

状态机接收到该消息之后,将状态切换成BleOnState。进入新的状态之后,告知AdapterService更新到新的状态。

  @Override
  public void enter() {
        int currState = getStateValue();
        mAdapterService.updateAdapterState(mPrevState, currState);
        mPrevState = currState;
  }

接着看AdapterService中是如何处理新状态STATE_BLE_ON的:

 void updateAdapterState(int prevState, int newState) {
    mAdapterProperties.setState(newState);
    if (mCallbacks != null) {
        int n = mCallbacks.beginBroadcast();
        for (int i = 0; i < n; i++) {
            try {
                mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState, newState);
            } catch (RemoteException e) {
                debugLog("updateAdapterState() - Callback #" + i + " failed (" + e + ")");
            }
        }
        mCallbacks.finishBroadcast();
    }
}

AdapterService接收到新状态之后,通过AIDL回调给BluetoothManagerService,接着看BluetoothManagerService是如何处理回调的:

 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
       @Override
       public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
           Message msg =
                   mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState);
           mHandler.sendMessage(msg);
      }
};

跟调用enable()的时候一样,同样是交给BluetoothHandler去处理:

// 省略了很多非核心代码
public void handleMessage(Message msg) {
     switch (msg.what) {
        case MESSAGE_BLUETOOTH_STATE_CHANGE: {
            int prevState = msg.arg1;
            int newState = msg.arg2;
            mState = newState;
            bluetoothStateChangeHandler(prevState, newState);
     }
}

private void bluetoothStateChangeHandler(int prevState, int newState) {
      if (newState == BluetoothAdapter.STATE_BLE_ON || newState == BluetoothAdapter.STATE_OFF) {
            boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
                   && newState == BluetoothAdapter.STATE_BLE_ON);
      if (!intermediate_off) {
            if (mBluetoothGatt != null || !mContext.getPackageManager()
                            .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
                   continueFromBleOnState();
             } 
            sendBleStateChanged(prevState, newState);
      } 
}

private void continueFromBleOnState() {
     try {
        mBluetoothLock.readLock().lock();
        if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) {
            // mBluetooth指的是AdapterService
            mBluetooth.onLeServiceUp();
            persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
        }
    } catch (RemoteException e) {
        Slog.e(TAG, "Unable to call onServiceUp", e);
    } finally {
        mBluetoothLock.readLock().unlock();
    }
}

BluetoothHandler获取到STATE_BLE_ON的状态信息之后,会继续通过AIDL让AdapterService将状态切换成OnState

 @Override
 public void onLeServiceUp() {
    AdapterService service = getService();
    if (service == null) {
        return;
    }
    service.onLeServiceUp();
}

void onLeServiceUp() {
    mAdapterStateMachine.sendMessage(AdapterState.USER_TURN_ON);
}

接着又回到状态机中切换状态,实现的代码很简单跟之前的状态切换类似,这就不再分析,最终BluetoothHandler会通过AIDL回调给BluetoothAdapter,最后会执行BluetoothStateChangeCallbackonBluetoothStateChange(boolean on)函数,但是这个回调接口被@hide了,因此我们无法监听此回调。

整个enable()过程就分析到这了,可能很多都没有分析到位,或者存在错误,后期再优化。

参考

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

推荐阅读更多精彩内容