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 getInstance(Context context, PhoneProxy[] phoneProxy, UiccController uiccController, CommandsInterface[] ci)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 getInstance()123 public static ProxyController getInstance() { 124 return sProxyController; 125 } 126 ProxyController(Context context, PhoneProxy[] phoneProxy, UiccController uiccController, CommandsInterface[] ci)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 updateDataConnectionTracker(int sub)160 public void updateDataConnectionTracker(int sub) { 161 mProxyPhones[sub].updateDataConnectionTracker(); 162 } 163 enableDataConnectivity(int sub)164 public void enableDataConnectivity(int sub) { 165 mProxyPhones[sub].setInternalDataEnabled(true); 166 } 167 disableDataConnectivity(int sub, Message dataCleanedUpMsg)168 public void disableDataConnectivity(int sub, 169 Message dataCleanedUpMsg) { 170 mProxyPhones[sub].setInternalDataEnabled(false, dataCleanedUpMsg); 171 } 172 updateCurrentCarrierInProvider(int sub)173 public void updateCurrentCarrierInProvider(int sub) { 174 mProxyPhones[sub].updateCurrentCarrierInProvider(); 175 } 176 registerForAllDataDisconnected(int subId, Handler h, int what, Object obj)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 unregisterForAllDataDisconnected(int subId, Handler h)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 isDataDisconnected(int subId)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 */ getRadioAccessFamily(int phoneId)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 */ setRadioCapability(RadioAccessFamily[] rafs)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 doSetRadioCapabilities(RadioAccessFamily[] rafs)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 */ onStartRadioCapabilityResponse(Message msg)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 */ onApplyRadioCapabilityResponse(Message msg)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 */ onNotificationRadioCapabilityChanged(Message msg)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 */ onFinishRadioCapabilityResponse(Message msg)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 onTimeoutRadioCapability(Message msg)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 issueFinish(int sessionId)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 completeRadioCapabilityTransaction()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 clearTransaction()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 resetRadioAccessFamilyStatusCounter()602 private void resetRadioAccessFamilyStatusCounter() { 603 mRadioAccessFamilyStatusCounter = mProxyPhones.length; 604 } 605 sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase, int radioFamily, String logicalModemId, int status, int eventId)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 getMaxRafSupported()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 getMinRafSupported()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 getLogicalModemIdFromRaf(int raf)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 logd(String string)663 private void logd(String string) { 664 Rlog.d(LOG_TAG, string); 665 } 666 loge(String string)667 private void loge(String string) { 668 Rlog.e(LOG_TAG, string); 669 } 670 dump(FileDescriptor fd, PrintWriter pw, String[] args)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