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