1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony; 18 19import java.util.ArrayList; 20import java.util.Random; 21 22import android.content.Context; 23import android.content.Intent; 24import android.os.AsyncResult; 25import android.os.Handler; 26import android.os.Message; 27import android.os.PowerManager; 28import android.os.PowerManager.WakeLock; 29import android.telephony.RadioAccessFamily; 30import android.telephony.Rlog; 31import android.telephony.TelephonyManager; 32import android.util.Log; 33 34import com.android.internal.telephony.PhoneSwitcher; 35import com.android.internal.telephony.uicc.UiccController; 36 37import java.io.FileDescriptor; 38import java.io.PrintWriter; 39import java.util.concurrent.atomic.AtomicInteger; 40import java.util.HashSet; 41 42public class ProxyController { 43 static final String LOG_TAG = "ProxyController"; 44 45 private static final int EVENT_NOTIFICATION_RC_CHANGED = 1; 46 private static final int EVENT_START_RC_RESPONSE = 2; 47 private static final int EVENT_APPLY_RC_RESPONSE = 3; 48 private static final int EVENT_FINISH_RC_RESPONSE = 4; 49 private static final int EVENT_TIMEOUT = 5; 50 51 private static final int SET_RC_STATUS_IDLE = 0; 52 private static final int SET_RC_STATUS_STARTING = 1; 53 private static final int SET_RC_STATUS_STARTED = 2; 54 private static final int SET_RC_STATUS_APPLYING = 3; 55 private static final int SET_RC_STATUS_SUCCESS = 4; 56 private static final int SET_RC_STATUS_FAIL = 5; 57 58 // The entire transaction must complete within this amount of time 59 // or a FINISH will be issued to each Logical Modem with the old 60 // Radio Access Family. 61 private static final int SET_RC_TIMEOUT_WAITING_MSEC = (45 * 1000); 62 63 //***** Class Variables 64 private static ProxyController sProxyController; 65 66 private Phone[] mPhones; 67 68 private UiccController mUiccController; 69 70 private CommandsInterface[] mCi; 71 72 private Context mContext; 73 74 private PhoneSwitcher mPhoneSwitcher; 75 76 //UiccPhoneBookController to use proper IccPhoneBookInterfaceManagerProxy object 77 private UiccPhoneBookController mUiccPhoneBookController; 78 79 //PhoneSubInfoController to use proper PhoneSubInfoProxy object 80 private PhoneSubInfoController mPhoneSubInfoController; 81 82 //UiccSmsController to use proper IccSmsInterfaceManager object 83 private UiccSmsController mUiccSmsController; 84 85 WakeLock mWakeLock; 86 87 // record each phone's set radio capability status 88 private int[] mSetRadioAccessFamilyStatus; 89 private int mRadioAccessFamilyStatusCounter; 90 private boolean mTransactionFailed = false; 91 92 private String[] mCurrentLogicalModemIds; 93 private String[] mNewLogicalModemIds; 94 95 // Allows the generation of unique Id's for radio capability request session id 96 private AtomicInteger mUniqueIdGenerator = new AtomicInteger(new Random().nextInt()); 97 98 // on-going radio capability request session id 99 private int mRadioCapabilitySessionId; 100 101 // Record new and old Radio Access Family (raf) configuration. 102 // The old raf configuration is used to restore each logical modem raf when FINISH is 103 // issued if any requests fail. 104 private int[] mNewRadioAccessFamily; 105 private int[] mOldRadioAccessFamily; 106 107 108 //***** Class Methods 109 public static ProxyController getInstance(Context context, Phone[] phone, 110 UiccController uiccController, CommandsInterface[] ci, PhoneSwitcher ps) { 111 if (sProxyController == null) { 112 sProxyController = new ProxyController(context, phone, uiccController, ci, ps); 113 } 114 return sProxyController; 115 } 116 117 public static ProxyController getInstance() { 118 return sProxyController; 119 } 120 121 private ProxyController(Context context, Phone[] phone, UiccController uiccController, 122 CommandsInterface[] ci, PhoneSwitcher phoneSwitcher) { 123 logd("Constructor - Enter"); 124 125 mContext = context; 126 mPhones = phone; 127 mUiccController = uiccController; 128 mCi = ci; 129 mPhoneSwitcher = phoneSwitcher; 130 131 mUiccPhoneBookController = new UiccPhoneBookController(mPhones); 132 mPhoneSubInfoController = new PhoneSubInfoController(mContext, mPhones); 133 mUiccSmsController = new UiccSmsController(mPhones); 134 mSetRadioAccessFamilyStatus = new int[mPhones.length]; 135 mNewRadioAccessFamily = new int[mPhones.length]; 136 mOldRadioAccessFamily = new int[mPhones.length]; 137 mCurrentLogicalModemIds = new String[mPhones.length]; 138 mNewLogicalModemIds = new String[mPhones.length]; 139 140 // wake lock for set radio capability 141 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 142 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); 143 mWakeLock.setReferenceCounted(false); 144 145 // Clear to be sure we're in the initial state 146 clearTransaction(); 147 for (int i = 0; i < mPhones.length; i++) { 148 mPhones[i].registerForRadioCapabilityChanged( 149 mHandler, EVENT_NOTIFICATION_RC_CHANGED, null); 150 } 151 logd("Constructor - Exit"); 152 } 153 154 public void updateDataConnectionTracker(int sub) { 155 mPhones[sub].updateDataConnectionTracker(); 156 } 157 158 public void enableDataConnectivity(int sub) { 159 mPhones[sub].setInternalDataEnabled(true, null); 160 } 161 162 public void disableDataConnectivity(int sub, 163 Message dataCleanedUpMsg) { 164 mPhones[sub].setInternalDataEnabled(false, dataCleanedUpMsg); 165 } 166 167 public void updateCurrentCarrierInProvider(int sub) { 168 mPhones[sub].updateCurrentCarrierInProvider(); 169 } 170 171 public void registerForAllDataDisconnected(int subId, Handler h, int what, Object obj) { 172 int phoneId = SubscriptionController.getInstance().getPhoneId(subId); 173 174 if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) { 175 mPhones[phoneId].registerForAllDataDisconnected(h, what, obj); 176 } 177 } 178 179 public void unregisterForAllDataDisconnected(int subId, Handler h) { 180 int phoneId = SubscriptionController.getInstance().getPhoneId(subId); 181 182 if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) { 183 mPhones[phoneId].unregisterForAllDataDisconnected(h); 184 } 185 } 186 187 public boolean isDataDisconnected(int subId) { 188 int phoneId = SubscriptionController.getInstance().getPhoneId(subId); 189 190 if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) { 191 return mPhones[phoneId].mDcTracker.isDisconnected(); 192 } else { 193 // if we can't find a phone for the given subId, it is disconnected. 194 return true; 195 } 196 } 197 198 /** 199 * Get phone radio type and access technology. 200 * 201 * @param phoneId which phone you want to get 202 * @return phone radio type and access technology for input phone ID 203 */ 204 public int getRadioAccessFamily(int phoneId) { 205 if (phoneId >= mPhones.length) { 206 return RadioAccessFamily.RAF_UNKNOWN; 207 } else { 208 return mPhones[phoneId].getRadioAccessFamily(); 209 } 210 } 211 212 /** 213 * Set phone radio type and access technology for each phone. 214 * 215 * @param rafs an RadioAccessFamily array to indicate all phone's 216 * new radio access family. The length of RadioAccessFamily 217 * must equal to phone count. 218 * @return false if another session is already active and the request is rejected. 219 */ 220 public boolean setRadioCapability(RadioAccessFamily[] rafs) { 221 if (rafs.length != mPhones.length) { 222 throw new RuntimeException("Length of input rafs must equal to total phone count"); 223 } 224 // Check if there is any ongoing transaction and throw an exception if there 225 // is one as this is a programming error. 226 synchronized (mSetRadioAccessFamilyStatus) { 227 for (int i = 0; i < mPhones.length; i++) { 228 if (mSetRadioAccessFamilyStatus[i] != SET_RC_STATUS_IDLE) { 229 // TODO: The right behaviour is to cancel previous request and send this. 230 loge("setRadioCapability: Phone[" + i + "] is not idle. Rejecting request."); 231 return false; 232 } 233 } 234 } 235 236 // Check we actually need to do anything 237 boolean same = true; 238 for (int i = 0; i < mPhones.length; i++) { 239 if (mPhones[i].getRadioAccessFamily() != rafs[i].getRadioAccessFamily()) { 240 same = false; 241 } 242 } 243 if (same) { 244 // All phones are already set to the requested raf 245 logd("setRadioCapability: Already in requested configuration, nothing to do."); 246 // It isn't really an error, so return true - everything is OK. 247 return true; 248 } 249 250 // Clear to be sure we're in the initial state 251 clearTransaction(); 252 253 // Keep a wake lock until we finish radio capability changed 254 mWakeLock.acquire(); 255 256 return doSetRadioCapabilities(rafs); 257 } 258 259 private boolean doSetRadioCapabilities(RadioAccessFamily[] rafs) { 260 // A new sessionId for this transaction 261 mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement(); 262 263 // Start timer to make sure all phones respond within a specific time interval. 264 // Will send FINISH if a timeout occurs. 265 Message msg = mHandler.obtainMessage(EVENT_TIMEOUT, mRadioCapabilitySessionId, 0); 266 mHandler.sendMessageDelayed(msg, SET_RC_TIMEOUT_WAITING_MSEC); 267 268 synchronized (mSetRadioAccessFamilyStatus) { 269 logd("setRadioCapability: new request session id=" + mRadioCapabilitySessionId); 270 resetRadioAccessFamilyStatusCounter(); 271 for (int i = 0; i < rafs.length; i++) { 272 int phoneId = rafs[i].getPhoneId(); 273 logd("setRadioCapability: phoneId=" + phoneId + " status=STARTING"); 274 mSetRadioAccessFamilyStatus[phoneId] = SET_RC_STATUS_STARTING; 275 mOldRadioAccessFamily[phoneId] = mPhones[phoneId].getRadioAccessFamily(); 276 int requestedRaf = rafs[i].getRadioAccessFamily(); 277 // TODO Set the new radio access family to the maximum of the requested & supported 278 // int supportedRaf = mPhones[i].getRadioAccessFamily(); 279 // mNewRadioAccessFamily[phoneId] = requestedRaf & supportedRaf; 280 mNewRadioAccessFamily[phoneId] = requestedRaf; 281 282 mCurrentLogicalModemIds[phoneId] = mPhones[phoneId].getModemUuId(); 283 // get the logical mode corresponds to new raf requested and pass the 284 // same as part of SET_RADIO_CAP APPLY phase 285 mNewLogicalModemIds[phoneId] = getLogicalModemIdFromRaf(requestedRaf); 286 logd("setRadioCapability: mOldRadioAccessFamily[" + phoneId + "]=" 287 + mOldRadioAccessFamily[phoneId]); 288 logd("setRadioCapability: mNewRadioAccessFamily[" + phoneId + "]=" 289 + mNewRadioAccessFamily[phoneId]); 290 sendRadioCapabilityRequest( 291 phoneId, 292 mRadioCapabilitySessionId, 293 RadioCapability.RC_PHASE_START, 294 mOldRadioAccessFamily[phoneId], 295 mCurrentLogicalModemIds[phoneId], 296 RadioCapability.RC_STATUS_NONE, 297 EVENT_START_RC_RESPONSE); 298 } 299 } 300 301 return true; 302 } 303 304 private Handler mHandler = new Handler() { 305 @Override 306 public void handleMessage(Message msg) { 307 logd("handleMessage msg.what=" + msg.what); 308 switch (msg.what) { 309 case EVENT_START_RC_RESPONSE: 310 onStartRadioCapabilityResponse(msg); 311 break; 312 313 case EVENT_APPLY_RC_RESPONSE: 314 onApplyRadioCapabilityResponse(msg); 315 break; 316 317 case EVENT_NOTIFICATION_RC_CHANGED: 318 onNotificationRadioCapabilityChanged(msg); 319 break; 320 321 case EVENT_FINISH_RC_RESPONSE: 322 onFinishRadioCapabilityResponse(msg); 323 break; 324 325 case EVENT_TIMEOUT: 326 onTimeoutRadioCapability(msg); 327 break; 328 329 default: 330 break; 331 } 332 } 333 }; 334 335 /** 336 * Handle START response 337 * @param msg obj field isa RadioCapability 338 */ 339 private void onStartRadioCapabilityResponse(Message msg) { 340 synchronized (mSetRadioAccessFamilyStatus) { 341 AsyncResult ar = (AsyncResult)msg.obj; 342 if (ar.exception != null) { 343 // just abort now. They didn't take our start so we don't have to revert 344 logd("onStartRadioCapabilityResponse got exception=" + ar.exception); 345 mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement(); 346 Intent intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_FAILED); 347 mContext.sendBroadcast(intent); 348 clearTransaction(); 349 return; 350 } 351 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 352 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 353 logd("onStartRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId 354 + " rc=" + rc); 355 return; 356 } 357 mRadioAccessFamilyStatusCounter--; 358 int id = rc.getPhoneId(); 359 if (((AsyncResult) msg.obj).exception != null) { 360 logd("onStartRadioCapabilityResponse: Error response session=" + rc.getSession()); 361 logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=FAIL"); 362 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; 363 mTransactionFailed = true; 364 } else { 365 logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=STARTED"); 366 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_STARTED; 367 } 368 369 if (mRadioAccessFamilyStatusCounter == 0) { 370 HashSet<String> modemsInUse = new HashSet<String>(mNewLogicalModemIds.length); 371 for (String modemId : mNewLogicalModemIds) { 372 if (!modemsInUse.add(modemId)) { 373 mTransactionFailed = true; 374 Log.wtf(LOG_TAG, "ERROR: sending down the same id for different phones"); 375 } 376 } 377 logd("onStartRadioCapabilityResponse: success=" + !mTransactionFailed); 378 if (mTransactionFailed) { 379 // Sends a variable number of requests, so don't resetRadioAccessFamilyCounter 380 // here. 381 issueFinish(mRadioCapabilitySessionId); 382 } else { 383 // All logical modem accepted the new radio access family, issue the APPLY 384 resetRadioAccessFamilyStatusCounter(); 385 for (int i = 0; i < mPhones.length; i++) { 386 sendRadioCapabilityRequest( 387 i, 388 mRadioCapabilitySessionId, 389 RadioCapability.RC_PHASE_APPLY, 390 mNewRadioAccessFamily[i], 391 mNewLogicalModemIds[i], 392 RadioCapability.RC_STATUS_NONE, 393 EVENT_APPLY_RC_RESPONSE); 394 395 logd("onStartRadioCapabilityResponse: phoneId=" + i + " status=APPLYING"); 396 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_APPLYING; 397 } 398 } 399 } 400 } 401 } 402 403 /** 404 * Handle APPLY response 405 * @param msg obj field isa RadioCapability 406 */ 407 private void onApplyRadioCapabilityResponse(Message msg) { 408 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 409 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 410 logd("onApplyRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId 411 + " rc=" + rc); 412 return; 413 } 414 logd("onApplyRadioCapabilityResponse: rc=" + rc); 415 if (((AsyncResult) msg.obj).exception != null) { 416 synchronized (mSetRadioAccessFamilyStatus) { 417 logd("onApplyRadioCapabilityResponse: Error response session=" + rc.getSession()); 418 int id = rc.getPhoneId(); 419 logd("onApplyRadioCapabilityResponse: phoneId=" + id + " status=FAIL"); 420 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; 421 mTransactionFailed = true; 422 } 423 } else { 424 logd("onApplyRadioCapabilityResponse: Valid start expecting notification rc=" + rc); 425 } 426 } 427 428 /** 429 * Handle the notification unsolicited response associated with the APPLY 430 * @param msg obj field isa RadioCapability 431 */ 432 private void onNotificationRadioCapabilityChanged(Message msg) { 433 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 434 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 435 logd("onNotificationRadioCapabilityChanged: Ignore session=" + mRadioCapabilitySessionId 436 + " rc=" + rc); 437 return; 438 } 439 synchronized (mSetRadioAccessFamilyStatus) { 440 logd("onNotificationRadioCapabilityChanged: rc=" + rc); 441 // skip the overdue response by checking sessionId 442 if (rc.getSession() != mRadioCapabilitySessionId) { 443 logd("onNotificationRadioCapabilityChanged: Ignore session=" 444 + mRadioCapabilitySessionId + " rc=" + rc); 445 return; 446 } 447 448 int id = rc.getPhoneId(); 449 if ((((AsyncResult) msg.obj).exception != null) || 450 (rc.getStatus() == RadioCapability.RC_STATUS_FAIL)) { 451 logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=FAIL"); 452 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; 453 mTransactionFailed = true; 454 } else { 455 logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=SUCCESS"); 456 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_SUCCESS; 457 // The modems may have been restarted and forgotten this 458 mPhoneSwitcher.resendDataAllowed(id); 459 mPhones[id].radioCapabilityUpdated(rc); 460 } 461 462 mRadioAccessFamilyStatusCounter--; 463 if (mRadioAccessFamilyStatusCounter == 0) { 464 logd("onNotificationRadioCapabilityChanged: APPLY URC success=" + 465 mTransactionFailed); 466 issueFinish(mRadioCapabilitySessionId); 467 } 468 } 469 } 470 471 /** 472 * Handle the FINISH Phase response 473 * @param msg obj field isa RadioCapability 474 */ 475 void onFinishRadioCapabilityResponse(Message msg) { 476 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 477 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 478 logd("onFinishRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId 479 + " rc=" + rc); 480 return; 481 } 482 synchronized (mSetRadioAccessFamilyStatus) { 483 logd(" onFinishRadioCapabilityResponse mRadioAccessFamilyStatusCounter=" 484 + mRadioAccessFamilyStatusCounter); 485 mRadioAccessFamilyStatusCounter--; 486 if (mRadioAccessFamilyStatusCounter == 0) { 487 completeRadioCapabilityTransaction(); 488 } 489 } 490 } 491 492 private void onTimeoutRadioCapability(Message msg) { 493 if (msg.arg1 != mRadioCapabilitySessionId) { 494 logd("RadioCapability timeout: Ignore msg.arg1=" + msg.arg1 + 495 "!= mRadioCapabilitySessionId=" + mRadioCapabilitySessionId); 496 return; 497 } 498 499 synchronized(mSetRadioAccessFamilyStatus) { 500 // timed-out. Clean up as best we can 501 for (int i = 0; i < mPhones.length; i++) { 502 logd("RadioCapability timeout: mSetRadioAccessFamilyStatus[" + i + "]=" + 503 mSetRadioAccessFamilyStatus[i]); 504 } 505 506 // Increment the sessionId as we are completing the transaction below 507 // so we don't want it completed when the FINISH phase is done. 508 int uniqueDifferentId = mUniqueIdGenerator.getAndIncrement(); 509 // send FINISH request with fail status and then uniqueDifferentId 510 mTransactionFailed = true; 511 issueFinish(uniqueDifferentId); 512 } 513 } 514 515 private void issueFinish(int sessionId) { 516 // Issue FINISH 517 synchronized(mSetRadioAccessFamilyStatus) { 518 for (int i = 0; i < mPhones.length; i++) { 519 logd("issueFinish: phoneId=" + i + " sessionId=" + sessionId 520 + " mTransactionFailed=" + mTransactionFailed); 521 mRadioAccessFamilyStatusCounter++; 522 sendRadioCapabilityRequest( 523 i, 524 sessionId, 525 RadioCapability.RC_PHASE_FINISH, 526 mOldRadioAccessFamily[i], 527 mCurrentLogicalModemIds[i], 528 (mTransactionFailed ? RadioCapability.RC_STATUS_FAIL : 529 RadioCapability.RC_STATUS_SUCCESS), 530 EVENT_FINISH_RC_RESPONSE); 531 if (mTransactionFailed) { 532 logd("issueFinish: phoneId: " + i + " status: FAIL"); 533 // At least one failed, mark them all failed. 534 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_FAIL; 535 } 536 } 537 } 538 } 539 540 private void completeRadioCapabilityTransaction() { 541 // Create the intent to broadcast 542 Intent intent; 543 logd("onFinishRadioCapabilityResponse: success=" + !mTransactionFailed); 544 if (!mTransactionFailed) { 545 ArrayList<RadioAccessFamily> phoneRAFList = new ArrayList<RadioAccessFamily>(); 546 for (int i = 0; i < mPhones.length; i++) { 547 int raf = mPhones[i].getRadioAccessFamily(); 548 logd("radioAccessFamily[" + i + "]=" + raf); 549 RadioAccessFamily phoneRC = new RadioAccessFamily(i, raf); 550 phoneRAFList.add(phoneRC); 551 } 552 intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_DONE); 553 intent.putParcelableArrayListExtra(TelephonyIntents.EXTRA_RADIO_ACCESS_FAMILY, 554 phoneRAFList); 555 556 // make messages about the old transaction obsolete (specifically the timeout) 557 mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement(); 558 559 // Reinitialize 560 clearTransaction(); 561 } else { 562 intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_FAILED); 563 564 // now revert. 565 mTransactionFailed = false; 566 RadioAccessFamily[] rafs = new RadioAccessFamily[mPhones.length]; 567 for (int phoneId = 0; phoneId < mPhones.length; phoneId++) { 568 rafs[phoneId] = new RadioAccessFamily(phoneId, mOldRadioAccessFamily[phoneId]); 569 } 570 doSetRadioCapabilities(rafs); 571 } 572 573 // Broadcast that we're done 574 mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE); 575 } 576 577 // Clear this transaction 578 private void clearTransaction() { 579 logd("clearTransaction"); 580 synchronized(mSetRadioAccessFamilyStatus) { 581 for (int i = 0; i < mPhones.length; i++) { 582 logd("clearTransaction: phoneId=" + i + " status=IDLE"); 583 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_IDLE; 584 mOldRadioAccessFamily[i] = 0; 585 mNewRadioAccessFamily[i] = 0; 586 mTransactionFailed = false; 587 } 588 589 if (mWakeLock.isHeld()) { 590 mWakeLock.release(); 591 } 592 } 593 } 594 595 private void resetRadioAccessFamilyStatusCounter() { 596 mRadioAccessFamilyStatusCounter = mPhones.length; 597 } 598 599 private void sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase, 600 int radioFamily, String logicalModemId, int status, int eventId) { 601 RadioCapability requestRC = new RadioCapability( 602 phoneId, sessionId, rcPhase, radioFamily, logicalModemId, status); 603 mPhones[phoneId].setRadioCapability( 604 requestRC, mHandler.obtainMessage(eventId)); 605 } 606 607 // This method will return max number of raf bits supported from the raf 608 // values currently stored in all phone objects 609 public int getMaxRafSupported() { 610 int[] numRafSupported = new int[mPhones.length]; 611 int maxNumRafBit = 0; 612 int maxRaf = RadioAccessFamily.RAF_UNKNOWN; 613 614 for (int len = 0; len < mPhones.length; len++) { 615 numRafSupported[len] = Integer.bitCount(mPhones[len].getRadioAccessFamily()); 616 if (maxNumRafBit < numRafSupported[len]) { 617 maxNumRafBit = numRafSupported[len]; 618 maxRaf = mPhones[len].getRadioAccessFamily(); 619 } 620 } 621 622 return maxRaf; 623 } 624 625 // This method will return minimum number of raf bits supported from the raf 626 // values currently stored in all phone objects 627 public int getMinRafSupported() { 628 int[] numRafSupported = new int[mPhones.length]; 629 int minNumRafBit = 0; 630 int minRaf = RadioAccessFamily.RAF_UNKNOWN; 631 632 for (int len = 0; len < mPhones.length; len++) { 633 numRafSupported[len] = Integer.bitCount(mPhones[len].getRadioAccessFamily()); 634 if ((minNumRafBit == 0) || (minNumRafBit > numRafSupported[len])) { 635 minNumRafBit = numRafSupported[len]; 636 minRaf = mPhones[len].getRadioAccessFamily(); 637 } 638 } 639 return minRaf; 640 } 641 642 // This method checks current raf values stored in all phones and 643 // whicheve phone raf matches with input raf, returns modemId from that phone 644 private String getLogicalModemIdFromRaf(int raf) { 645 String modemUuid = null; 646 647 for (int phoneId = 0; phoneId < mPhones.length; phoneId++) { 648 if (mPhones[phoneId].getRadioAccessFamily() == raf) { 649 modemUuid = mPhones[phoneId].getModemUuId(); 650 break; 651 } 652 } 653 return modemUuid; 654 } 655 656 private void logd(String string) { 657 Rlog.d(LOG_TAG, string); 658 } 659 660 private void loge(String string) { 661 Rlog.e(LOG_TAG, string); 662 } 663} 664