[go: nahoru, domu]

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