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