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