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