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