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
getInstance(Context context, PhoneProxy[] phoneProxy, UiccController uiccController, CommandsInterface[] ci)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 
getInstance()123     public static ProxyController getInstance() {
124         return sProxyController;
125     }
126 
ProxyController(Context context, PhoneProxy[] phoneProxy, UiccController uiccController, CommandsInterface[] ci)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 
updateDataConnectionTracker(int sub)160     public void updateDataConnectionTracker(int sub) {
161         mProxyPhones[sub].updateDataConnectionTracker();
162     }
163 
enableDataConnectivity(int sub)164     public void enableDataConnectivity(int sub) {
165         mProxyPhones[sub].setInternalDataEnabled(true);
166     }
167 
disableDataConnectivity(int sub, Message dataCleanedUpMsg)168     public void disableDataConnectivity(int sub,
169             Message dataCleanedUpMsg) {
170         mProxyPhones[sub].setInternalDataEnabled(false, dataCleanedUpMsg);
171     }
172 
updateCurrentCarrierInProvider(int sub)173     public void updateCurrentCarrierInProvider(int sub) {
174         mProxyPhones[sub].updateCurrentCarrierInProvider();
175     }
176 
registerForAllDataDisconnected(int subId, Handler h, int what, Object obj)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 
unregisterForAllDataDisconnected(int subId, Handler h)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 
isDataDisconnected(int subId)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      */
getRadioAccessFamily(int phoneId)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      */
setRadioCapability(RadioAccessFamily[] rafs)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 
doSetRadioCapabilities(RadioAccessFamily[] rafs)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      */
onStartRadioCapabilityResponse(Message msg)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      */
onApplyRadioCapabilityResponse(Message msg)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      */
onNotificationRadioCapabilityChanged(Message msg)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      */
onFinishRadioCapabilityResponse(Message msg)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 
onTimeoutRadioCapability(Message msg)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 
issueFinish(int sessionId)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 
completeRadioCapabilityTransaction()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
clearTransaction()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 
resetRadioAccessFamilyStatusCounter()602     private void resetRadioAccessFamilyStatusCounter() {
603         mRadioAccessFamilyStatusCounter = mProxyPhones.length;
604     }
605 
sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase, int radioFamily, String logicalModemId, int status, int eventId)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
getMaxRafSupported()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
getMinRafSupported()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
getLogicalModemIdFromRaf(int raf)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 
logd(String string)663     private void logd(String string) {
664         Rlog.d(LOG_TAG, string);
665     }
666 
loge(String string)667     private void loge(String string) {
668         Rlog.e(LOG_TAG, string);
669     }
670 
dump(FileDescriptor fd, PrintWriter pw, String[] args)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