Camera2 FrameWork層分析

在Camera2 App中我們去打開相機時缺厉,最終是調用了mCameraManager.openCamera(cameraId)桃犬。我們就從這里開始分析Camera2 的FrameWork層。openCamera()最終是調用了CameraManager.openCameraDeviceUserAsync()我們直接來看這個函數

/**frameworks/base/core/java/android/hardware/camera2/CameraManager.java**/
private CameraDevice openCameraDeviceUserAsync(String cameraId,
        CameraDevice.StateCallback callback, Handler handler, final int uid)
        throws CameraAccessException {
    CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
    CameraDevice device = null;

    synchronized (mLock) {

        ICameraDeviceUser cameraUser = null;

        android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
                new android.hardware.camera2.impl.CameraDeviceImpl(
                    cameraId,
                    callback,
                    handler,
                    characteristics,
                    mContext.getApplicationInfo().targetSdkVersion);

        ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();

        try {
            if (supportsCamera2ApiLocked(cameraId)) {
                // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
                ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
                if (cameraService == null) {
                    throw new ServiceSpecificException(
                        ICameraService.ERROR_DISCONNECTED,
                        "Camera service is currently unavailable");
                }
                cameraUser = cameraService.connectDevice(callbacks, cameraId,
                        mContext.getOpPackageName(), uid);
            } else {
                // Use legacy camera implementation for HAL1 devices
                int id;
                try {
                    id = Integer.parseInt(cameraId);
                } catch (NumberFormatException e) {
                    throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
                            + cameraId);
                }

                Log.i(TAG, "Using legacy camera HAL.");
                cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
            }
        } catch (ServiceSpecificException e) {
            if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
                throw new AssertionError("Should've gone down the shim path");
            } else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
                    e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
                    e.errorCode == ICameraService.ERROR_DISABLED ||
                    e.errorCode == ICameraService.ERROR_DISCONNECTED ||
                    e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
                // Received one of the known connection errors
                // The remote camera device cannot be connected to, so
                // set the local camera to the startup error state
                deviceImpl.setRemoteFailure(e);

                if (e.errorCode == ICameraService.ERROR_DISABLED ||
                        e.errorCode == ICameraService.ERROR_DISCONNECTED ||
                        e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
                    // Per API docs, these failures call onError and throw
                    throwAsPublicException(e);
                }
            } else {
                // Unexpected failure - rethrow
                throwAsPublicException(e);
            }
        } catch (RemoteException e) {
            // Camera service died - act as if it's a CAMERA_DISCONNECTED case
            ServiceSpecificException sse = new ServiceSpecificException(
                ICameraService.ERROR_DISCONNECTED,
                "Camera service is currently unavailable");
            deviceImpl.setRemoteFailure(sse);
            throwAsPublicException(sse);
        }

        // TODO: factor out callback to be non-nested, then move setter to constructor
        // For now, calling setRemoteDevice will fire initial
        // onOpened/onUnconfigured callbacks.
        // This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
        // cameraUser dies during setup.
        deviceImpl.setRemoteDevice(cameraUser);
        device = deviceImpl;
    }

    return device;
}

在這段代碼中我們新建了一個android.hardware.camera2.impl.CameraDeviceImpl對象衔统,并且向其中保存了遠端設備并把它返回了鹿榜。我們先來分析下遠端設備cameraUser的獲取。在HAL3.2+的時候

/**frameworks/base/core/java/android/hardware/camera2/CameraManager.java**/
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
cameraUser = cameraService.connectDevice(callbacks, cameraId,
                        mContext.getOpPackageName(), uid);

這里第一句很容易知道這是通過了Android的Binder機制來獲取了遠端CameraService的一個代理锦爵。關于CameraService的啟動時機以及初始化舱殿,下節(jié)會詳細介紹。下面分析CameraService.connectDevice()

/**/frameworks/av/services/camera/libcameraservice/CameraService.cpp**/
Status CameraService::connectDevice(
        const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
        const String16& cameraId,
        const String16& clientPackageName,
        int clientUid,
        /*out*/
        sp<hardware::camera2::ICameraDeviceUser>* device) {

    ATRACE_CALL();
    Status ret = Status::ok();
    String8 id = String8(cameraId);
    sp<CameraDeviceClient> client = nullptr;
    ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
            clientUid, USE_CALLING_PID, API_2,
            /*legacyMode*/ false, /*shimUpdateOnly*/ false,
            /*out*/client);

    if(!ret.isOk()) {
        logRejected(id, getCallingPid(), String8(clientPackageName),
                ret.toString8());
        return ret;
    }

    *device = client;
    return ret;

這里可以看到connectDevice()函數實際返回了一個CameraDeviceCilent對象险掀,而這個對象是由函數connectHelper()返回的沪袭,函數如下:

/**frameworks/base/core/java/android/hardware/camera2/CameraManager.java**/
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
        int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
        apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
        /*out*/sp<CLIENT>& device) {
    binder::Status ret = binder::Status::ok();

    String8 clientName8(clientPackageName);

    /* Do something in */
    ......
    /* Do something out */

        sp<BasicClient> tmp = nullptr;
        if(!(ret = makeClient(this, cameraCb, clientPackageName, cameraId, facing, clientPid,
                clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,
                /*out*/&tmp)).isOk()) {
            return ret;
        }
        client = static_cast<CLIENT*>(tmp.get());

        LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
                __FUNCTION__);

        err = client->initialize(mCameraProviderManager);

    /* Do something in */
    ......
    /* Do something out */

    // Important: release the mutex here so the client can call back into the service from its
    // destructor (can be at the end of the call)
    device = client;
    return ret;
}

這里先是調用了makeCilent()函數返回一個BaseClient對象,然后將這個BaseClient對象轉型為了一個CameraDeviceCilent對象樟氢,然后執(zhí)行它的初始化函數冈绊,最后將這個對象返回。

/**frameworks/base/core/java/android/hardware/camera2/CameraManager.java**/
Status CameraService::makeClient(const sp<CameraService>& cameraService,
        const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
        int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
        int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
        /*out*/sp<BasicClient>* client) {

    if (halVersion < 0 || halVersion == deviceVersion) {
        // Default path: HAL version is unspecified by caller, create CameraClient
        // based on device version reported by the HAL.
        switch(deviceVersion) {
          case CAMERA_DEVICE_API_VERSION_1_0:
            /* Do something in */
            ......
            /* Do something out */
          case CAMERA_DEVICE_API_VERSION_3_0:
          case CAMERA_DEVICE_API_VERSION_3_1:
          case CAMERA_DEVICE_API_VERSION_3_2:
          case CAMERA_DEVICE_API_VERSION_3_3:
          case CAMERA_DEVICE_API_VERSION_3_4:
            if (effectiveApiLevel == API_1) { // Camera1 API route
                sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                *client = new Camera2Client(cameraService, tmp, packageName, cameraIdToInt(cameraId),
                        facing, clientPid, clientUid, servicePid, legacyMode);
            } else { // Camera2 API route
                sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
                        static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
                *client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
                        facing, clientPid, clientUid, servicePid);
            }
            break;
          default:
            // Should not be reachable
            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                    "Camera device \"%s\" has unknown HAL version %d",
                    cameraId.string(), deviceVersion);
        }
    } else {
        /* Do something in */
        ......
        /* Do something out */
    }
    return Status::ok();
}

可以看到在Camera2 API時埠啃,最終創(chuàng)建了一個CameraDeviceCilent對象并一路向上返回死宣,最終被保存在CameraManager中新建的CameraDeviceImpl對象的mRemoteDevice中。知道了deviceImpl.setRemoteDevice(cameraUser);中的cameraUser到底是什么霸妹,我們再來看看這個方法做了什么

/**/frameworks/base/core/java/android/hardware/camera2/Impl/CameraDeviceImpl.java**/
 public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
        synchronized(mInterfaceLock) {
            // TODO: Move from decorator to direct binder-mediated exceptions
            // If setRemoteFailure already called, do nothing
            if (mInError) return;

            mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);

            IBinder remoteDeviceBinder = remoteDevice.asBinder();
            // For legacy camera device, remoteDevice is in the same process, and
            // asBinder returns NULL.
            if (remoteDeviceBinder != null) {
                try {
                    remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
                } catch (RemoteException e) {
                    CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);

                    throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
                            "The camera device has encountered a serious error");
                }
            }

            mDeviceHandler.post(mCallOnOpened);
            mDeviceHandler.post(mCallOnUnconfigured);
        }
    }

private final Runnable mCallOnOpened = new Runnable() {
        @Override
        public void run() {
            StateCallbackKK sessionCallback = null;
            synchronized(mInterfaceLock) {
                if (mRemoteDevice == null) return; // Camera already closed

                sessionCallback = mSessionStateCallback;
            }
            if (sessionCallback != null) {
                sessionCallback.onOpened(CameraDeviceImpl.this);
            }
            mDeviceCallback.onOpened(CameraDeviceImpl.this);
        }
    };

這里mDeviceHandler就是我們創(chuàng)建deviceImpl傳入的handler十电,mDeviceCallback就是我們自己callback也就是我們自己打開相機時寫的那個回調。這里就明白了當CameraDeviceCilent創(chuàng)建成功并且通過CameraDeviceImpl.setRemoteDevice()設置給CameraDeviceImpl的時候就會回調相機打開成功的函數叹螟,而函數中的CameraDevice實際就是CameraDeviceImpl鹃骂,可以看到CameraDeviceImpl確實繼承了CameraDevice
下圖總結了這一段的流程罢绽。

返回CameraDeviceClient.png

接著我們看CameraDeviceCilent的構造函數:

/**frameworks\av\services\camera\libcameraservice\api2\CameraDeviceClient.cpp**/
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
        const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
        const String16& clientPackageName,
        const String8& cameraId,
        int cameraFacing,
        int clientPid,
        uid_t clientUid,
        int servicePid) :
    Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
                cameraId, cameraFacing, clientPid, clientUid, servicePid),
    mInputStream(),
    mStreamingRequestId(REQUEST_ID_NONE),
    mRequestIdCounter(0) {

    ATRACE_CALL();
    ALOGI("CameraDeviceClient %s: Opened", cameraId.string());
}

可以看到這里就是調用了父類的構造函數畏线,和一些初始化。CameraDeviceClient新建完成后在CameraService.connectHelper中執(zhí)行了client->initialize(mCameraProviderManager);

/**frameworks\av\services\camera\libcameraservice\api2\CameraDeviceClient.cpp**/
status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager) {
    return initializeImpl(manager);
}

template<typename TProviderPtr>
status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr) {
    ATRACE_CALL();
    status_t res;

    res = Camera2ClientBase::initialize(providerPtr);
    if (res != OK) {
        return res;
    }

    String8 threadName;
    mFrameProcessor = new FrameProcessorBase(mDevice);
    threadName = String8::format("CDU-%s-FrameProc", mCameraIdStr.string());
    mFrameProcessor->run(threadName.string());

    mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
                                      FRAME_PROCESSOR_LISTENER_MAX_ID,
                                      /*listener*/this,
                                      /*sendPartials*/true);

    return OK;
}

這里執(zhí)行了父類的初始化函數良价,然后進行了FrameProcessor 的創(chuàng)建與初始化配置等等寝殴,這個東西可能是用于處理上傳的每幀數據的蒿叠。上面執(zhí)行了父類也就是Camera2ClientBase的構造函數,這里又執(zhí)行了它的初始化函數蚣常,接下來著重分析類Camera2ClientBase市咽。先看構造函數:

/**frameworks\av\services\camera\libcameraservice\common\Camera2ClientBase.cpp**/
template <typename TClientBase>
Camera2ClientBase<TClientBase>::Camera2ClientBase(
        const sp<CameraService>& cameraService,
        const sp<TCamCallbacks>& remoteCallback,
        const String16& clientPackageName,
        const String8& cameraId,
        int cameraFacing,
        int clientPid,
        uid_t clientUid,
        int servicePid):
        TClientBase(cameraService, remoteCallback, clientPackageName,
                cameraId, cameraFacing, clientPid, clientUid, servicePid),
        mSharedCameraCallbacks(remoteCallback),
        mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
        mDeviceActive(false)
{
    ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
            String8(clientPackageName).string(), clientPid, clientUid);

    mInitialClientPid = clientPid;
    mDevice = new Camera3Device(cameraId);
    LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}

這里就是需要注意創(chuàng)建了一個Camera3Device對象,接著分析Camera2ClientBase的初始化函數:

/**frameworks\av\services\camera\libcameraservice\common\Camera2ClientBase.cpp**/
template <typename TClientBase>
status_t Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager) {
    return initializeImpl(manager);
}

template <typename TClientBase>
template <typename TProviderPtr>
status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr) {
    ATRACE_CALL();
    ALOGV("%s: Initializing client for camera %s", __FUNCTION__,
          TClientBase::mCameraIdStr.string());
    status_t res;

    // Verify ops permissions
    res = TClientBase::startCameraOps();
    if (res != OK) {
        return res;
    }

    if (mDevice == NULL) {
        ALOGE("%s: Camera %s: No device connected",
                __FUNCTION__, TClientBase::mCameraIdStr.string());
        return NO_INIT;
    }

    res = mDevice->initialize(providerPtr);
    if (res != OK) {
        ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
                __FUNCTION__, TClientBase::mCameraIdStr.string(), strerror(-res), res);
        return res;
    }

    wp<CameraDeviceBase::NotificationListener> weakThis(this);
    res = mDevice->setNotifyCallback(weakThis);

    return OK;
}

注意此處抵蚊,TClientBase 對應 CameraDeviceClientBase施绎,而 TProviderPtr對應的是 CameraProviderManager。這里調用了Camera3Device的初始化函數贞绳,此前我們已經新建了Camera3Device對象谷醉,調用了構造函數。

/**frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp*/
Camera3Device::Camera3Device(const String8 &id):
        mId(id),
        mOperatingMode(NO_MODE),
        mIsConstrainedHighSpeedConfiguration(false),
        mStatus(STATUS_UNINITIALIZED),
        mStatusWaiters(0),
        mUsePartialResult(false),
        mNumPartialResults(1),
        mTimestampOffset(0),
        mNextResultFrameNumber(0),
        mNextReprocessResultFrameNumber(0),
        mNextShutterFrameNumber(0),
        mNextReprocessShutterFrameNumber(0),
        mListener(NULL),
        mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID)
{
    ATRACE_CALL();
    camera3_callback_ops::notify = &sNotify;
    camera3_callback_ops::process_capture_result = &sProcessCaptureResult;
    ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
}

這里主要進行了參數的初始化以及兩個回調接口的設置冈闭。

/**frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp*/
status_t Camera3Device::initialize(sp<CameraProviderManager> manager) {
    ATRACE_CALL();
    Mutex::Autolock il(mInterfaceLock);
    Mutex::Autolock l(mLock);

    ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
    if (mStatus != STATUS_UNINITIALIZED) {
        CLOGE("Already initialized!");
        return INVALID_OPERATION;
    }
    if (manager == nullptr) return INVALID_OPERATION;

    sp<ICameraDeviceSession> session;
    ATRACE_BEGIN("CameraHal::openSession");
    status_t res = manager->openSession(mId.string(), this,
            /*out*/ &session);
    ATRACE_END();
    if (res != OK) {
        SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
        return res;
    }

    /* Do something in */
    ......
    /* Do something out */

    return initializeCommonLocked();
}

這里可以看到通過CameraProviderManager開啟了遠端session

/**frameworks\av\services\camera\libcameraservice\common\CameraProviderManager.cpp**/
status_t CameraProviderManager::openSession(const std::string &id,
        const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback,
        /*out*/
        sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session) {

    std::lock_guard<std::mutex> lock(mInterfaceMutex);

    auto deviceInfo = findDeviceInfoLocked(id,
            /*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
    if (deviceInfo == nullptr) return NAME_NOT_FOUND;

    auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);

    Status status;
    hardware::Return<void> ret;
    ret = deviceInfo3->mInterface->open(callback, [&status, &session]
            (Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
                status = s;
                if (status == Status::OK) {
                    *session = cameraSession;
                }
            });
    if (!ret.isOk()) {
        ALOGE("%s: Transaction error opening a session for camera device %s: %s",
                __FUNCTION__, id.c_str(), ret.description().c_str());
        return DEAD_OBJECT;
    }
    return mapToStatusT(status);
}

首先調用findDeviceInfoLocked()俱尼,獲取 HAL3 相關的 DeviceInfo3,這個東西在服務啟動與初始化的時候就已經創(chuàng)建出來萎攒,并保存下來了遇八。通過遠端調用 CameraDeviceopen() 方法,創(chuàng)建 CameraDeviceSession實例并將其本地調用接口通過入參session返回躺酒。 (DeviceInfo3這個類的 mInterface成員類型是 ICameraDevice押蚤,通過它可以調用遠端 CameraDevice 中的方法。)這里就進入了HAL層了羹应,CameraDevice.open()中最終調用了CameraDevice.createDeviceSession()創(chuàng)建了一個CameraDeviceSession揽碘。
這一段的流程圖如下:

Framework流程圖.png

Camera2架構.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市园匹,隨后出現的幾起案子雳刺,更是在濱河造成了極大的恐慌,老刑警劉巖裸违,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掖桦,死亡現場離奇詭異,居然都是意外死亡供汛,警方通過查閱死者的電腦和手機枪汪,發(fā)現死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怔昨,“玉大人雀久,你說我怎么就攤上這事〕靡ǎ” “怎么了赖捌?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長矮烹。 經常有香客問我越庇,道長罩锐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任卤唉,我火速辦了婚禮涩惑,結果婚禮上,老公的妹妹穿的比我還像新娘搬味。我一直安慰自己境氢,他們只是感情好,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布碰纬。 她就那樣靜靜地躺著,像睡著了一般问芬。 火紅的嫁衣襯著肌膚如雪悦析。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天此衅,我揣著相機與錄音强戴,去河邊找鬼。 笑死挡鞍,一個胖子當著我的面吹牛骑歹,可吹牛的內容都是我干的。 我是一名探鬼主播墨微,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼道媚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了翘县?” 一聲冷哼從身側響起最域,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锈麸,沒想到半個月后镀脂,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡忘伞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年薄翅,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氓奈。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡翘魄,死狀恐怖,靈堂內的尸體忽然破棺而出探颈,到底是詐尸還是另有隱情熟丸,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布伪节,位于F島的核電站光羞,受9級特大地震影響绩鸣,放射性物質發(fā)生泄漏。R本人自食惡果不足惜纱兑,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一呀闻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧潜慎,春花似錦捡多、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至倒信,卻和暖如春科贬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鳖悠。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工榜掌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乘综。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓憎账,卻偏偏與公主長得像,于是被迫代替她去往敵國和親卡辰。 傳聞我的和親對象是個殘疾皇子胞皱,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354