| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <log/log.h> |
| #include <set> |
| #include <stdexcept> |
| |
| #include "Proxycontroller.h" |
| #include "common.h" |
| #include "network.h" |
| #include "data.h" |
| #include "bitset" |
| #include "utils.h" |
| #include "WorldPhoneUtil.h" |
| |
| #define LOG_TAG "DEMO_Proxy_controller" |
| |
| constexpr int Proxy_controller::EVENT_NOTIFICATION_RC_CHANGED; |
| constexpr int Proxy_controller::EVENT_START_RC_RESPONSE; |
| constexpr int Proxy_controller::EVENT_APPLY_RC_RESPONSE; |
| constexpr int Proxy_controller::EVENT_FINISH_RC_RESPONSE; |
| constexpr int Proxy_controller::EVENT_TIMEOUT; |
| |
| const int Proxy_controller::SET_RC_STATUS_IDLE = 0; |
| const int Proxy_controller::SET_RC_STATUS_STARTING = 1; |
| const int Proxy_controller::SET_RC_STATUS_STARTED = 2; |
| const int Proxy_controller::SET_RC_STATUS_APPLYING = 3; |
| const int Proxy_controller::SET_RC_STATUS_SUCCESS = 4; |
| const int Proxy_controller::SET_RC_STATUS_FAIL = 5; |
| |
| const std::string Proxy_controller::PROPERTY_CAPABILITY_SWITCH = "persist.vendor.radio.simswitch"; |
| const std::string Proxy_controller::PROPERTY_CAPABILITY_SWITCH_STATE = "persist.vendor.radio.simswitchstate"; |
| |
| // event 1-5 is defined in ProxyController |
| const int Proxy_controller::EVENT_RADIO_AVAILABLE = 6; |
| const int Proxy_controller::EVENT_RIL_CONNECTED = 7; |
| |
| // marker for retry cause |
| const int Proxy_controller::RC_RETRY_CAUSE_NONE = 0; |
| const int Proxy_controller::RC_RETRY_CAUSE_WORLD_MODE_SWITCHING = 1; |
| const int Proxy_controller::RC_RETRY_CAUSE_CAPABILITY_SWITCHING = 2; |
| const int Proxy_controller::RC_RETRY_CAUSE_IN_CALL = 3; |
| const int Proxy_controller::RC_RETRY_CAUSE_RADIO_UNAVAILABLE = 4; |
| const int Proxy_controller::RC_RETRY_CAUSE_AIRPLANE_MODE = 5; |
| const int Proxy_controller::RC_RETRY_CAUSE_RESULT_ERROR = 6; |
| |
| // marker for switch conditions pre-checking |
| const int Proxy_controller::RC_DO_SWITCH = 0; |
| const int Proxy_controller::RC_NO_NEED_SWITCH = 1; |
| const int Proxy_controller::RC_CANNOT_SWITCH = 2; |
| |
| Proxy_controller* Proxy_controller::sInstance = nullptr; |
| // The entire transaction must complete within this amount of time |
| // or a FINISH will be issued to each Logical Modem with the old |
| // Radio Access Family. |
| const int Proxy_controller::SET_RC_TIMEOUT_WAITING_MSEC = (45 * 1000); |
| |
| Proxy_controller::Proxy_controller() :mRadioCapabilitySessionId(0), mTransactionFailed(false){ |
| //***** Class Variables |
| mIsCapSwitching = false; |
| mHasRegisterWorldModeReceiver = false; |
| mHasRegisterPhoneStateReceiver = false; |
| mHasRegisterEccStateReceiver = false; |
| mIsRildReconnected = false; |
| mSetRafRetryCause = RC_RETRY_CAUSE_NONE; |
| // Exception counter |
| onExceptionCount = 0; |
| clearTransaction(); |
| } |
| |
| Proxy_controller::~Proxy_controller() { |
| // TODO Auto-generated destructor stub |
| } |
| |
| Proxy_controller::Handle_thread::Handle_thread(): m_looper(NULL){ |
| RLOGD("RequestHandleThread created"); |
| } |
| |
| Proxy_controller::Handle_thread::~Handle_thread() { |
| RLOGD("RequestHandleThread destroyed"); |
| } |
| |
| sp<Looper> Proxy_controller::Handle_thread::getLooper() { |
| return m_looper; |
| } |
| |
| bool Proxy_controller::Handle_thread::threadLoop() { |
| RLOGD("Handler threadLoop"); |
| m_looper = Looper::prepare(0); |
| int result; |
| do { |
| result = m_looper->pollAll(-1); |
| RLOGD("Handler threadLoop, pull message result = %d", result); |
| } while (result == Looper::POLL_WAKE || result == Looper::POLL_CALLBACK); |
| return true; |
| } |
| |
| Proxy_controller::Request_message::Request_message(): what(0), slot(-1),e(RIL_E_SUCCESS), is_rc_set(true),id(-1){ |
| |
| } |
| |
| void Proxy_controller::init() { |
| handle_thread = new Handle_thread(); |
| handle_thread->run(); |
| } |
| |
| Proxy_controller *Proxy_controller::getInstance() { |
| if (sInstance == NULL) { |
| sInstance = new Proxy_controller(); |
| sInstance->init(); |
| } |
| return sInstance; |
| } |
| |
| sp<Proxy_controller::Request_handler> Proxy_controller::sendMessage(sp<Request_message> msg, int delayms) { |
| RLOGD("sendMessage msg what=%d delayms=%d", msg->what, delayms); |
| // Create a handler to handle this message |
| sp<Request_handler> handler = new Request_handler(this); |
| handler->msg = msg; |
| // Sand message to looper |
| if(handle_thread.get()) { |
| sp<Looper> looper = handle_thread->getLooper(); |
| if(looper.get()) { |
| if (delayms > 0) { |
| looper->sendMessageDelayed(ms2ns(delayms),handler, handler->m_dummyMsg); |
| } else { |
| looper->sendMessage(handler, handler->m_dummyMsg); |
| } |
| } else { |
| RLOGD("looper"); |
| } |
| } else { |
| RLOGD("handle_thread"); |
| } |
| |
| return handler; |
| } |
| |
| void Proxy_controller::handle_request_resp(RIL_RadioCapability* cap, RIL_Errno e, int slot) { |
| if(m_eventId[slot] < 0) { |
| RLOGD("handle_request_resp cap is null.m_eventId[%d]=%d", slot, m_eventId[slot]); |
| return; |
| } |
| RLOGD("handle_request_resp what[%d]: %d , phase: %d", slot,m_eventId[slot], cap->phase); |
| // Create a request message |
| sp<Request_message> msg = new Request_message(); |
| msg->what = m_eventId[slot]; |
| if(cap != NULL) { |
| msg->cap = (*cap); |
| } else { |
| msg->is_rc_set = false; |
| RLOGD("handle_request_resp[slot%d]: cap is null", slot); |
| } |
| msg->e = e; |
| msg->slot = slot; |
| RLOGD("handle_request_resp logicalModemUuid: %s , phase: %d, rat: %d, session: %d, status: %d, version: %d", |
| msg->cap.logicalModemUuid, msg->cap.phase, msg->cap.rat, msg->cap.session, msg->cap.status, msg->cap.version); |
| sendMessage(msg, 0); |
| } |
| |
| void Proxy_controller::issueFinish(int sessionId) { |
| m_mutex.lock(); |
| for (int i = 0; i < SIM_COUNT; i++) { |
| RLOGD("issueFinish: phoneId=%d sessionId= %d mTransactionFailed=%d", i, sessionId, mTransactionFailed); |
| mRadioAccessFamilyStatusCounter++; |
| sendRadioCapabilityRequest( |
| i, |
| sessionId, |
| RadioCapabilityPhase(RC_PHASE_FINISH), |
| (mTransactionFailed ? mOldRadioAccessFamily[i] : |
| mNewRadioAccessFamily[i]), |
| (mTransactionFailed ? mCurrentLogicalModemIds[i] : |
| mNewLogicalModemIds[i]), |
| (mTransactionFailed ? RadioCapabilityStatus(RC_STATUS_FAIL) : |
| RadioCapabilityStatus(RC_STATUS_SUCCESS)), |
| EVENT_FINISH_RC_RESPONSE); |
| if (mTransactionFailed) { |
| RLOGD("issueFinish: phoneId: %d status: FAIL", i); |
| // At least one failed, mark them all failed. |
| mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_FAIL; |
| } |
| } |
| m_mutex.unlock(); |
| } |
| |
| void Proxy_controller::onStartRadioCapabilityResponse(sp<Request_message> msg) { |
| m_mutex.lock(); |
| |
| RIL_RadioCapability rc = msg->cap; |
| if ((rc.session != mRadioCapabilitySessionId.load())) { |
| RLOGD("onStartRadioCapabilityResponse: Ignore session=%d,rc.logicalModemUuid = %d, rc.phase = %d, rc.rat = %d, rc.session = %d, rc.status = %d, rc.version = %d", |
| mRadioCapabilitySessionId.load(), rc.logicalModemUuid,rc.phase,rc.rat,rc.session,rc.status,rc.version); |
| return; |
| } |
| mRadioAccessFamilyStatusCounter--; |
| int id = msg->slot; |
| if (msg->e != RIL_E_SUCCESS) { |
| RLOGD("onStartRadioCapabilityResponse: Error response session=%d", rc.session); |
| RLOGD("onStartRadioCapabilityResponse: phoneId=%d status=FAIL", id); |
| mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; |
| mTransactionFailed = true; |
| } else { |
| RLOGD("onStartRadioCapabilityResponse: phoneId=%d status=STARTED", id); |
| mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_STARTED; |
| } |
| |
| if (mRadioAccessFamilyStatusCounter == 0) { |
| /** |
| std::set<std::string> modemsInUse; |
| for (auto modemId : mNewLogicalModemIds) { |
| if (!(modemsInUse.insert(modemId).second)) { |
| mTransactionFailed = true; |
| RLOGD("ERROR: sending down the same id for different phones"); |
| } |
| } |
| **/ |
| RLOGD("onStartRadioCapabilityResponse: success=%d", !mTransactionFailed); |
| if (mTransactionFailed) { |
| // Sends a variable number of requests, so don't resetRadioAccessFamilyCounter |
| // here. |
| m_mutex.unlock(); |
| issueFinish(mRadioCapabilitySessionId.load()); |
| return; |
| } else { |
| // All logical modem accepted the new radio access family, issue the APPLY |
| resetRadioAccessFamilyStatusCounter(); |
| for (int i = 0; i < SIM_COUNT; i++) { |
| sendRadioCapabilityRequest( |
| i, |
| mRadioCapabilitySessionId.load(), |
| RadioCapabilityPhase(RC_PHASE_APPLY), |
| mNewRadioAccessFamily[i], |
| mNewLogicalModemIds[i], |
| RadioCapabilityStatus(RC_STATUS_NONE), |
| EVENT_APPLY_RC_RESPONSE); |
| |
| RLOGD("onStartRadioCapabilityResponse: phoneId=%d status=APPLYING", i); |
| mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_APPLYING; |
| } |
| } |
| } |
| m_mutex.unlock(); |
| } |
| |
| void Proxy_controller::onApplyRadioCapabilityErrorHandler(sp<Request_message> msg){ |
| |
| } |
| void Proxy_controller::onApplyExceptionHandler(sp<Request_message> msg){ |
| |
| } |
| |
| void Proxy_controller::onApplyRadioCapabilityResponse(sp<Request_message> msg) { |
| RIL_RadioCapability rc = msg->cap; |
| if ((rc.session != mRadioCapabilitySessionId.load())) { |
| RLOGD("onApplyRadioCapabilityResponse: Ignore session=%d,rc.logicalModemUuid = %d, rc.phase = %d, rc.rat = %d, rc.session = %d, rc.status = %d, rc.version = %d", |
| mRadioCapabilitySessionId.load(), rc.logicalModemUuid,rc.phase,rc.rat,rc.session,rc.status,rc.version); |
| /// M: handle rc error, retry sim switch if possible. @{ |
| onApplyRadioCapabilityErrorHandler(msg); |
| /// @} |
| return; |
| } |
| RLOGD("onApplyRadioCapabilityResponse: rc.logicalModemUuid = %d, rc.phase = %d, rc.rat = %d, rc.session = %d, rc.status = %d, rc.version = %d", |
| mRadioCapabilitySessionId.load(), rc.logicalModemUuid,rc.phase,rc.rat,rc.session,rc.status,rc.version); |
| if (msg->e != RIL_E_SUCCESS) { |
| m_mutex.lock(); |
| RLOGD("onApplyRadioCapabilityResponse: Error response session=%d",rc.session); |
| int id = msg->slot; |
| /// M: handle exception, retry sim switch if possible. @{ |
| onApplyExceptionHandler(msg); |
| /// @} |
| RLOGD("onApplyRadioCapabilityResponse: phoneId=%d status=FAIL", id); |
| mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; |
| mTransactionFailed = true; |
| m_mutex.unlock(); |
| } else { |
| RLOGD("onApplyRadioCapabilityResponse: Valid start expecting notification rc.logicalModemUuid = %d, rc.phase = %d, rc.rat = %d, rc.session = %d, rc.status = %d, rc.version = %d", |
| mRadioCapabilitySessionId.load(), rc.logicalModemUuid,rc.phase,rc.rat,rc.session,rc.status,rc.version); |
| } |
| } |
| |
| void Proxy_controller::handle_message_notify(RIL_RadioCapability* cap,int slot) { |
| sp<Request_message> msg = new Request_message(); |
| msg->what = EVENT_NOTIFICATION_RC_CHANGED; |
| if(cap != NULL) { |
| msg->cap = (*cap); |
| } else { |
| msg->is_rc_set = false; |
| RLOGD("handle_request_resp[slot%d]: cap is null", slot); |
| } |
| msg->slot = slot; |
| RLOGD("handle_request_resp logicalModemUuid: %s , phase: %d, rat: %d, session: %d, status: %d, version: %d", |
| msg->cap.logicalModemUuid, msg->cap.phase, msg->cap.rat, msg->cap.session, msg->cap.status, msg->cap.version); |
| sendMessage(msg, 0); |
| } |
| |
| void Proxy_controller::onNotificationRadioCapabilityChanged(sp<Request_message> msg) { |
| RIL_RadioCapability rc = msg->cap; |
| if (msg->is_rc_set == false || (rc.session != mRadioCapabilitySessionId.load())) { |
| RLOGD("onNotificationRadioCapabilityChanged: Ignore session=%d,rc.logicalModemUuid = %d, rc.phase = %d, rc.rat = %d, rc.session = %d, rc.status = %d, rc.version = %d", |
| mRadioCapabilitySessionId.load(), rc.logicalModemUuid,rc.phase,rc.rat,rc.session,rc.status,rc.version); |
| return; |
| } |
| m_mutex.lock(); |
| RLOGD("onNotificationRadioCapabilityChanged: rc.logicalModemUuid = %d, rc.phase = %d, rc.rat = %d, rc.session = %d, rc.status = %d, rc.version = %d", |
| rc.logicalModemUuid,rc.phase,rc.rat,rc.session,rc.status,rc.version); |
| |
| int id = msg->slot; |
| if (msg-> e != RIL_E_SUCCESS || |
| (rc.status == RadioCapabilityStatus(RC_STATUS_FAIL))) { |
| RLOGD("onNotificationRadioCapabilityChanged: phoneId=%d status=FAIL", id); |
| mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; |
| mTransactionFailed = true; |
| } else { |
| RLOGD("onNotificationRadioCapabilityChanged: phoneId=%d status=SUCCESS(%d)", id, !mTransactionFailed); |
| mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_SUCCESS; |
| // The modems may have been restarted and forgotten this |
| |
| RequestInfo *info = creatRILInfoAndInit(RIL_REQUEST_ALLOW_DATA, OTHER, (RIL_SOCKET_ID)id); |
| |
| int switch_id = get_default_sim_data_for_switch(); |
| RLOGD("onNotificationRadioCapabilityChanged: phoneId=%d switch_id=%d", id, switch_id); |
| char* argv[2] = {"RIL_REQUEST_ALLOW_DATA","0"}; |
| if(id == switch_id) { |
| argv[1] = "1"; |
| } |
| setDataAllowed(2, argv, RIL_SOCKET_ID(id), info); |
| } |
| |
| mRadioAccessFamilyStatusCounter--; |
| if (mRadioAccessFamilyStatusCounter == 0) { |
| RLOGD("onNotificationRadioCapabilityChanged: APPLY URC success=%d",!mTransactionFailed); |
| m_mutex.unlock(); |
| issueFinish(mRadioCapabilitySessionId.load()); |
| return; |
| } |
| m_mutex.unlock(); |
| } |
| |
| void Proxy_controller::completeRadioCapabilityTransaction() { |
| RLOGD("completeRadioCapabilityTransaction: success=%d" , !mTransactionFailed); |
| if (!mTransactionFailed) { |
| |
| |
| // make messages about the old transaction obsolete (specifically the timeout) |
| //mRadioCapabilitySessionId++; |
| |
| // Reinitialize |
| clearTransaction(); |
| android::emResultNotify("default data slot switch success\n"); |
| } else { |
| android::emResultNotify("default data slot switch fail, now retry\n"); |
| // now revert. |
| mTransactionFailed = false; |
| std::vector<RIL_RadioAccessFamily> rafs = {RAF_UNKNOWN, RAF_UNKNOWN}; |
| for (int phoneId = 0; phoneId < SIM_COUNT; phoneId++) { |
| rafs[phoneId] = (RIL_RadioAccessFamily)mOldRadioAccessFamily[phoneId]; |
| } |
| doSetRadioCapabilities(rafs); |
| } |
| |
| } |
| |
| void Proxy_controller::onFinishRadioCapabilityResponse(sp<Request_message> msg){ |
| RIL_RadioCapability rc = msg->cap;; |
| if (msg->is_rc_set == false || (rc.session != mRadioCapabilitySessionId.load())) { |
| RLOGD("onFinishRadioCapabilityResponse: Ignore session=%d,rc.logicalModemUuid = %d, rc.phase = %d, rc.rat = %d, rc.session = %d, rc.status = %d, rc.version = %d", |
| mRadioCapabilitySessionId.load(), rc.logicalModemUuid,rc.phase,rc.rat,rc.session,rc.status,rc.version); |
| return; |
| } |
| m_mutex.lock(); |
| RLOGD("onFinishRadioCapabilityResponse mRadioAccessFamilyStatusCounter=%d",mRadioAccessFamilyStatusCounter); |
| mRadioAccessFamilyStatusCounter--; |
| if (mRadioAccessFamilyStatusCounter == 0) { |
| m_mutex.unlock(); |
| completeRadioCapabilityTransaction(); |
| return; |
| } |
| m_mutex.unlock(); |
| } |
| |
| void Proxy_controller::onTimeoutRadioCapability(sp<Request_message> msg){ |
| if (msg->id != mRadioCapabilitySessionId.load()) { |
| RLOGD("RadioCapability timeout: Ignore msg->id=%d != mRadioCapabilitySessionId.load()=%d", msg->id,mRadioCapabilitySessionId.load()); |
| return; |
| } |
| |
| m_mutex.lock(); |
| // timed-out. Clean up as best we can |
| for (int i = 0; i < SIM_COUNT; i++) { |
| RLOGD("RadioCapability timeout: mSetRadioAccessFamilyStatus[%d]=%d",i,mSetRadioAccessFamilyStatus[i]); |
| } |
| |
| // Increment the sessionId as we are completing the transaction below |
| // so we don't want it completed when the FINISH phase is done. |
| mRadioCapabilitySessionId++; |
| |
| // Reset the status counter as existing session failed |
| mRadioAccessFamilyStatusCounter = 0; |
| |
| // send FINISH request with fail status and then uniqueDifferentId |
| mTransactionFailed = true; |
| m_mutex.unlock(); |
| issueFinish(mRadioCapabilitySessionId.load()); |
| } |
| |
| void Proxy_controller::Request_handler::sendMessage(sp<Request_message> msg, int delayms) { |
| RLOGD("Proxy_controller::Request_handler, sendMessage msg what=%d delayms=%d", msg->what, delayms); |
| // Sand message to looper |
| this->msg = msg; |
| if (delayms > 0) { |
| proxy_controller->handle_thread->getLooper()->sendMessageDelayed(ms2ns(delayms), |
| this, this->m_dummyMsg); |
| } else { |
| proxy_controller->handle_thread->getLooper()->sendMessage(this, this->m_dummyMsg); |
| } |
| return ; |
| } |
| |
| void Proxy_controller::Request_handler::handleMessage(const Message& message) { |
| |
| RLOGD("handleMessage msg->what: %d", msg->what); |
| switch( msg->what){ |
| case EVENT_START_RC_RESPONSE: |
| { |
| proxy_controller->onStartRadioCapabilityResponse(msg); |
| break; |
| } |
| case EVENT_APPLY_RC_RESPONSE: |
| { |
| proxy_controller->onApplyRadioCapabilityResponse(msg); |
| break; |
| } |
| case EVENT_NOTIFICATION_RC_CHANGED: |
| { |
| proxy_controller->onNotificationRadioCapabilityChanged(msg); |
| break; |
| } |
| case EVENT_FINISH_RC_RESPONSE: |
| { |
| proxy_controller->onFinishRadioCapabilityResponse(msg); |
| break; |
| } |
| case EVENT_TIMEOUT: |
| { |
| proxy_controller->onTimeoutRadioCapability(msg); |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| void Proxy_controller::clearTransaction() { |
| RLOGD("clearTransaction"); |
| m_mutex.lock(); |
| mSetRadioAccessFamilyStatus.clear(); |
| mOldRadioAccessFamily.clear(); |
| mNewRadioAccessFamily.clear(); |
| m_eventId.clear(); |
| mCurrentLogicalModemIds.clear(); |
| mNewLogicalModemIds.clear(); |
| for (int i = 0; i < 2; i++) { |
| RLOGD("clearTransaction: phoneId=%d status=IDLE",i); |
| mSetRadioAccessFamilyStatus.push_back(SET_RC_STATUS_IDLE); |
| mOldRadioAccessFamily.push_back(0); |
| mNewRadioAccessFamily.push_back(0); |
| mCurrentLogicalModemIds.push_back(""); |
| mNewLogicalModemIds.push_back(""); |
| mTransactionFailed = false; |
| m_eventId.push_back(-1); |
| } |
| if(handle_thread.get()) { |
| sp<Looper> looper = handle_thread->getLooper(); |
| if(looper.get()) { |
| if(timeout_handle.get()) { |
| looper->removeMessages(timeout_handle); |
| } else { |
| RLOGD("clearTransaction,timeout_handle"); |
| } |
| } else { |
| RLOGD("clearTransaction,looper"); |
| } |
| } else { |
| RLOGD("clearTransaction,handle_thread"); |
| } |
| m_mutex.unlock(); |
| } |
| |
| int Proxy_controller::checkRadioCapabilitySwitchConditions(std::vector<RIL_RadioAccessFamily> rafs) { |
| m_mutex.lock(); |
| mNextRafs = rafs; |
| |
| // check if still switching |
| if (mIsCapSwitching == true) { |
| //throw new RuntimeException("is still switching"); |
| RLOGD("keep it and return,because capability swithing"); |
| mSetRafRetryCause = RC_RETRY_CAUSE_CAPABILITY_SWITCHING; |
| return RC_NO_NEED_SWITCH; |
| } else if (mSetRafRetryCause == RC_RETRY_CAUSE_CAPABILITY_SWITCHING) { |
| RLOGD("setCapability, mIsCapSwitching is not switching, can switch"); |
| mSetRafRetryCause = RC_RETRY_CAUSE_NONE; |
| } |
| mIsCapSwitching = true; |
| m_mutex.lock(); |
| |
| // check if capability switch disabled |
| if (utils::mtk_property_get_bool("ro.vendor.mtk_disable_cap_switch", false) == true) { |
| mNextRafs.clear(); |
| completeRadioCapabilityTransaction(); |
| RLOGD("skip switching because mtk_disable_cap_switch is true"); |
| return RC_NO_NEED_SWITCH; |
| } |
| // check FTA mode |
| if (utils::mtk_property_get_int32("vendor.gsm.gcf.testmode", 0) == 2) { |
| mNextRafs.clear(); |
| completeRadioCapabilityTransaction(); |
| RLOGD("skip switching because FTA mode"); |
| return RC_NO_NEED_SWITCH; |
| } |
| // check EM disable mode |
| if (utils::mtk_property_get_int32("persist.vendor.radio.simswitch.emmode", 1) == 0) { |
| mNextRafs.clear(); |
| completeRadioCapabilityTransaction(); |
| RLOGD("skip switching because EM disable mode"); |
| return RC_NO_NEED_SWITCH; |
| } |
| |
| // check world mode switching |
| if (WorldPhoneUtil::isWorldPhoneSupport()) { |
| if (!WorldPhoneUtil::isWorldModeSupport()) { |
| if (/*ModemSwitchHandler.isModemTypeSwitching()*/!isRadioAvailable((RIL_SOCKET_ID)Radio_capability_switch_util::get_main_capability_phone_id())) { |
| RLOGD("world mode switching."); |
| if (!mHasRegisterWorldModeReceiver) { |
| mHasRegisterWorldModeReceiver = true; |
| } |
| mSetRafRetryCause = RC_RETRY_CAUSE_WORLD_MODE_SWITCHING; |
| m_mutex.lock(); |
| mIsCapSwitching = false; |
| m_mutex.unlock(); |
| return RC_CANNOT_SWITCH; |
| } |
| } else if (mSetRafRetryCause == RC_RETRY_CAUSE_WORLD_MODE_SWITCHING) { |
| if (mHasRegisterWorldModeReceiver) { |
| mHasRegisterWorldModeReceiver = false; |
| mSetRafRetryCause = RC_RETRY_CAUSE_NONE; |
| } |
| } |
| } |
| |
| // check call state |
| if (!(is_call_state_idle(0) || is_call_state_idle(1))) { |
| //throw new RuntimeException("in call, fail to set RAT for phones"); |
| RLOGD("setCapability in calling, fail to set RAT for phones"); |
| if (!mHasRegisterPhoneStateReceiver) { |
| mHasRegisterPhoneStateReceiver = true; |
| } |
| mSetRafRetryCause = RC_RETRY_CAUSE_IN_CALL; |
| m_mutex.lock(); |
| mIsCapSwitching = false; |
| m_mutex.unlock(); |
| return RC_CANNOT_SWITCH; |
| } else if (isEccInProgress()) { |
| RLOGD("setCapability in ECC, fail to set RAT for phones"); |
| if (!mHasRegisterEccStateReceiver) { |
| mHasRegisterEccStateReceiver = true; |
| } |
| mSetRafRetryCause = RC_RETRY_CAUSE_IN_CALL; |
| m_mutex.lock(); |
| mIsCapSwitching = false; |
| m_mutex.unlock(); |
| return RC_CANNOT_SWITCH; |
| } else if (mSetRafRetryCause == RC_RETRY_CAUSE_IN_CALL) { |
| if (mHasRegisterPhoneStateReceiver) { |
| mHasRegisterPhoneStateReceiver = false; |
| mSetRafRetryCause = RC_RETRY_CAUSE_NONE; |
| } |
| if (mHasRegisterEccStateReceiver) { |
| mHasRegisterEccStateReceiver = false; |
| mSetRafRetryCause = RC_RETRY_CAUSE_NONE; |
| } |
| } |
| |
| // check radio available |
| for (int i = 0; i < SIM_COUNT; i++) { |
| if (!isRadioAvailable((RIL_SOCKET_ID)i)) { |
| //throw new RuntimeException("Phone" + i + " is not available"); |
| mSetRafRetryCause = RC_RETRY_CAUSE_RADIO_UNAVAILABLE; |
| //mCi[i].registerForAvailable(mMtkHandler, EVENT_RADIO_AVAILABLE, null); |
| RLOGD("setCapability fail,Phone%d is not available", i); |
| m_mutex.lock(); |
| mIsCapSwitching = false; |
| m_mutex.unlock(); |
| return RC_CANNOT_SWITCH; |
| } else if (mSetRafRetryCause == RC_RETRY_CAUSE_RADIO_UNAVAILABLE) { |
| //mCi[i].unregisterForAvailable(mMtkHandler); |
| if (i == SIM_COUNT - 1) { |
| mSetRafRetryCause = RC_RETRY_CAUSE_NONE; |
| } |
| } |
| } |
| |
| int switchStatus = utils::mtk_property_get_int32(PROPERTY_CAPABILITY_SWITCH.c_str(), 1); |
| // check parameter |
| bool bIsboth3G = false; |
| bool bIsMajorPhone = false; |
| int newMajorPhoneId = 0; |
| for (int i = 0; i < rafs.size(); i++) { |
| bIsMajorPhone = false; |
| if ((rafs[i] & RIL_RadioAccessFamily::RAF_GPRS) > 0) { |
| bIsMajorPhone = true; |
| } |
| |
| if (bIsMajorPhone) { |
| newMajorPhoneId = i; |
| if (newMajorPhoneId == (switchStatus - 1)) { |
| RLOGD("no change, skip setRadioCapability"); |
| mSetRafRetryCause = RC_RETRY_CAUSE_NONE; |
| mNextRafs.clear(); |
| completeRadioCapabilityTransaction(); |
| return RC_NO_NEED_SWITCH; |
| } |
| if (bIsboth3G) { |
| RLOGD("set more than one 3G phone, fail"); |
| m_mutex.lock(); |
| mIsCapSwitching = false; |
| m_mutex.unlock(); |
| throw std::runtime_error("input parameter is incorrect"); |
| } else { |
| bIsboth3G = true; |
| } |
| } |
| } |
| if (bIsboth3G == false) { |
| m_mutex.lock(); |
| mIsCapSwitching = false; |
| m_mutex.unlock(); |
| throw std::runtime_error("input parameter is incorrect - no 3g phone"); |
| } |
| |
| // check operator spec |
| if (!isNeedSimSwitch(newMajorPhoneId, SIM_COUNT)) { |
| RLOGD("check sim card type and skip setRadioCapability"); |
| mSetRafRetryCause = RC_RETRY_CAUSE_NONE; |
| mNextRafs.clear(); |
| completeRadioCapabilityTransaction(); |
| return RC_NO_NEED_SWITCH; |
| } |
| |
| // if (!WorldPhoneUtil::isWorldModeSupport() && WorldPhoneUtil::isWorldPhoneSupport()) { |
| // WorldPhoneUtil.getWorldPhone().notifyRadioCapabilityChange(newMajorPhoneId); |
| // } |
| RLOGD("checkRadioCapabilitySwitchConditions, do switch"); |
| return RC_DO_SWITCH; |
| } |
| |
| bool Proxy_controller::isEccInProgress() { |
| bool inEcm = utils::mtk_property_get_bool("ril.cdma.inecmmode", false); |
| return inEcm; |
| } |
| |
| bool Proxy_controller::isNeedSimSwitch(int majorPhoneId, int phoneNum) { |
| RLOGD("OMisNeedSimSwitch, majorPhoneId = %d ", majorPhoneId); |
| return !Radio_capability_switch_util::isSkipCapabilitySwitch(majorPhoneId, phoneNum); |
| } |
| |
| bool Proxy_controller::set_Radio_Capability(std::vector<RIL_RadioAccessFamily> rafs) { |
| if (rafs.size() != SIM_COUNT) { |
| RLOGD("Length of input rafs must equal to total phone count"); |
| } |
| // Check if there is any ongoing transaction and throw an exception if there |
| // is one as this is a programming error. |
| m_mutex.lock(); |
| for (int i = 0; i < rafs.size(); i++) { |
| if (mSetRadioAccessFamilyStatus[i] != SET_RC_STATUS_IDLE) { |
| // TODO: The right behaviour is to cancel previous request and send this. |
| RLOGE("setRadioCapability: Phone[%d] is not idle. Rejecting request.", i); |
| return false; |
| } |
| } |
| m_mutex.unlock(); |
| |
| // Clear to be sure we're in the initial state |
| clearTransaction(); |
| |
| return doSetRadioCapabilities(rafs); |
| } |
| |
| void Proxy_controller::resetRadioAccessFamilyStatusCounter() { |
| mRadioAccessFamilyStatusCounter = SIM_COUNT; |
| } |
| |
| std::string Proxy_controller::getLogicalModemIdFromRaf(int raf) { |
| std::string modemUui; |
| |
| for (int phoneId = 0; phoneId < SIM_COUNT; phoneId++) { |
| if (get_radio_capa(phoneId).rat == raf) { |
| modemUui = get_radio_capa(phoneId).logicalModemUuid; |
| break; |
| } |
| } |
| return modemUui; |
| } |
| |
| void Proxy_controller::sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase, |
| int radioFamily, std::string logicalModemId, int status, int eventId){ |
| RequestInfo *info = creatRILInfoAndInit(RIL_REQUEST_SET_RADIO_CAPABILITY, OTHER, (RIL_SOCKET_ID)phoneId); |
| |
| char* argv[7] = {"RIL_REQUEST_SET_RADIO_CAPABILITY", |
| const_cast<char*>(std::to_string(RIL_RADIO_CAPABILITY_VERSION).c_str()), |
| const_cast<char*>(std::to_string(sessionId).c_str()), |
| const_cast<char*>(std::to_string(rcPhase).c_str()), |
| const_cast<char*>(std::to_string(radioFamily).c_str()), |
| const_cast<char*>(logicalModemId.c_str()), |
| const_cast<char*>(std::to_string(status).c_str()) |
| }; |
| setRadioCapability(7, argv,(RIL_SOCKET_ID)phoneId, info); |
| m_eventId[phoneId] = eventId; |
| } |
| |
| bool Proxy_controller::doSetRadioCapabilities(std::vector<RIL_RadioAccessFamily> rafs) { |
| // A new sessionId for this transaction |
| mRadioCapabilitySessionId++; |
| // Start timer to make sure all phones respond within a specific time interval. |
| // Will send FINISH if a timeout occurs. |
| sp<Request_message> msg = new Request_message(); |
| msg->what = EVENT_TIMEOUT; |
| msg->id = mRadioCapabilitySessionId.load(); |
| timeout_handle = sendMessage(msg, SET_RC_TIMEOUT_WAITING_MSEC); |
| |
| m_mutex.lock(); |
| RLOGD("setRadioCapability: new request session id=%d", mRadioCapabilitySessionId.load()); |
| resetRadioAccessFamilyStatusCounter(); |
| for (int i = 0; i < rafs.size(); i++) { |
| RLOGD("setRadioCapability: phoneId=%d status=STARTING", i); |
| mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_STARTING; |
| mOldRadioAccessFamily[i] = get_radio_capa(i).rat; |
| int requestedRaf = rafs[i]; |
| // TODO Set the new radio access family to the maximum of the requested & supported |
| // int supportedRaf = mPhones[i].getRadioAccessFamily(); |
| // mNewRadioAccessFamily[i] = requestedRaf & supportedRaf; |
| mNewRadioAccessFamily[i] = requestedRaf; |
| |
| mCurrentLogicalModemIds[i] = get_radio_capa(i).logicalModemUuid; |
| // get the logical mode corresponds to new raf requested and pass the |
| // same as part of SET_RADIO_CAP APPLY phase |
| mNewLogicalModemIds[i] = getLogicalModemIdFromRaf(requestedRaf); |
| RLOGD("setRadioCapability: mOldRadioAccessFamily[%d]=%d", i,mOldRadioAccessFamily[i]); |
| RLOGD("setRadioCapability: mNewRadioAccessFamily[%d]=%d", i,mNewRadioAccessFamily[i]); |
| sendRadioCapabilityRequest( |
| i, |
| mRadioCapabilitySessionId.load(), |
| RadioCapabilityPhase(RC_PHASE_START), |
| mOldRadioAccessFamily[i], |
| mCurrentLogicalModemIds[i], |
| RadioCapabilityStatus(RC_STATUS_NONE), |
| EVENT_START_RC_RESPONSE); |
| } |
| m_mutex.unlock(); |
| return true; |
| } |