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