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