blob: d173c71419dfea1a3915e831047da4e9b916b1c4 [file] [log] [blame]
/*
* 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;
}