Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e982e13 authored by Mengjun Leng's avatar Mengjun Leng Committed by ssizon
Browse files

Fetching IMSI from RUIM properly

Regarding to multi-mode SIM, the AID might be empty, so that
IMSI is read from a wrong application.

To fix it, parse IMSI from EF file to overwrite the IMSI if
it is empty.

Change-Id: I61723aa4db73d136e72dad37a3b6db4dc77e0e4b
CRs-Fixed: 2525186
parent f8f8d5a1
Loading
Loading
Loading
Loading
+67 −29
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.MccTable;
@@ -208,16 +209,6 @@ public class RuimRecords extends IccRecords {
        }
    }

    @UnsupportedAppUsage
    private int adjstMinDigits (int digits) {
        // Per C.S0005 section 2.3.1.
        digits += 111;
        digits = (digits % 10 == 0)?(digits - 10):digits;
        digits = ((digits / 10) % 10 == 0)?(digits - 100):digits;
        digits = ((digits / 100) % 10 == 0)?(digits - 1000):digits;
        return digits;
    }

    /**
     * Returns the 5 or 6 digit MCC/MNC of the operator that
     *  provided the RUIM card. Returns null of RUIM is not yet ready
@@ -376,7 +367,8 @@ public class RuimRecords extends IccRecords {
        }
    }

    private class EfCsimImsimLoaded implements IccRecordLoaded {
    @VisibleForTesting
    public class EfCsimImsimLoaded implements IccRecordLoaded {
        @Override
        public String getEfName() {
            return "EF_CSIM_IMSIM";
@@ -385,31 +377,74 @@ public class RuimRecords extends IccRecords {
        @Override
        public void onRecordLoaded(AsyncResult ar) {
            byte[] data = (byte[]) ar.result;
            if (VDBG) log("CSIM_IMSIM=" + IccUtils.bytesToHexString(data));
            if (data == null || data.length < 10) {
                if (DBG) log("Invalid IMSI from EF_CSIM_IMSIM");
                return;
            }
            if (DBG) Rlog.pii(LOG_TAG, IccUtils.bytesToHexString(data));
            // C.S0065 section 5.2.2 for IMSI_M encoding
            // C.S0005 section 2.3.1 for MIN encoding in IMSI_M.
            boolean provisioned = ((data[7] & 0x80) == 0x80);

            if (provisioned) {
                final String imsi = decodeImsi(data);
                if (TextUtils.isEmpty(mImsi)) {
                    mImsi = imsi;
                    if (DBG) log("IMSI=" + Rlog.pii(LOG_TAG, mImsi));
                }
                if (null != imsi) {
                    mMin = imsi.substring(5, 15);
                }
                if (DBG) log("min present=" + Rlog.pii(LOG_TAG, mMin));
            } else {
                if (DBG) log("min not present");
            }
        }

        private int decodeImsiDigits(int digits, int length) {
            // Per C.S0005 section 2.3.1.
            for (int i = 0, denominator = 1; i < length; i++) {
                digits += denominator;
                if ((digits / denominator) % 10 == 0) {
                    digits = digits - (10 * denominator);
                }
                denominator *= 10;
            }
            return digits;
        }

        /**
         * Decode utility to decode IMSI from data read from EF_IMSIM
         * Please refer to
         * C.S0065 section 5.2.2 for IMSI_M encoding
         * C.S0005 section 2.3.1 for MIN encoding in IMSI_M.
         */
        private String decodeImsi(byte[] data) {
            // Retrieve the MCC and digits 11 and 12
            int mcc_data = ((0x03 & data[9]) << 8) | (0xFF & data[8]);
            int mcc = decodeImsiDigits(mcc_data, 3);
            int digits_11_12_data = data[6] & 0x7f;
            int digits_11_12 = decodeImsiDigits(digits_11_12_data, 2);

            // Retrieve 10 MIN digits
            int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]);
            int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6;
            int digit7 = 0x0F & (data[4] >> 2);
            if (digit7 > 0x09) digit7 = 0;
            int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]);
                first3digits = adjstMinDigits(first3digits);
                second3digits = adjstMinDigits(second3digits);
                last3digits = adjstMinDigits(last3digits);

            first3digits = decodeImsiDigits(first3digits, 3);
            second3digits = decodeImsiDigits(second3digits, 3);
            last3digits = decodeImsiDigits(last3digits, 3);

            StringBuilder builder = new StringBuilder();
            builder.append(String.format(Locale.US, "%03d", mcc));
            builder.append(String.format(Locale.US, "%02d", digits_11_12));
            builder.append(String.format(Locale.US, "%03d", first3digits));
            builder.append(String.format(Locale.US, "%03d", second3digits));
            builder.append(String.format(Locale.US, "%d", digit7));
            builder.append(String.format(Locale.US, "%03d", last3digits));
                mMin = builder.toString();
                if (DBG) log("min present=" + Rlog.pii(LOG_TAG, mMin));
            } else {
                if (DBG) log("min not present");
            }
            return  builder.toString();
        }
    }

@@ -852,8 +887,11 @@ public class RuimRecords extends IccRecords {

        if (DBG) log("fetchRuimRecords " + mRecordsToLoad);

        if (!TextUtils.isEmpty(mParentApp.getAid())
                || mParentApp.getUiccProfile().getNumApplications() <= 1) {
            mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
            mRecordsToLoad++;
        }

        mFh.loadEFTransparent(EF_ICCID,
                obtainMessage(EVENT_GET_ICCID_DONE));
+4 −6
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ public class UiccProfile extends IccCard {
    private int mGsmUmtsSubscriptionAppIndex;
    private int mCdmaSubscriptionAppIndex;
    private int mImsSubscriptionAppIndex;
    private int mApplicationCount;
    private UiccCardApplication[] mUiccApplications =
            new UiccCardApplication[IccCardStatus.CARD_MAX_APPS];
    private Context mContext;
@@ -955,6 +956,7 @@ public class UiccProfile extends IccCard {
            mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;
            mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;
            mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;
            mApplicationCount = ics.mApplications.length;
            mContext = c;
            mCi = ci;
            mTelephonyManager = (TelephonyManager) mContext.getSystemService(
@@ -1520,13 +1522,9 @@ public class UiccProfile extends IccCard {
     * Returns number of applications on this card
     */
    public int getNumApplications() {
        int count = 0;
        for (UiccCardApplication a : mUiccApplications) {
            if (a != null) {
                count++;
            }
        synchronized (mLock) {
            return mApplicationCount;
        }
        return count;
    }

    /**
+88 −0
Original line number Diff line number Diff line
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

package com.android.internal.telephony.uicc;

import org.mockito.Mock;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import org.mockito.MockitoAnnotations;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.android.internal.telephony.TelephonyTest;

import android.content.Context;
import android.os.AsyncResult;
import android.os.HandlerThread;

public class RuimRecordsTest extends TelephonyTest {

    private RuimRecords mRuimRecords;

    private class RuimRecordsTestHandler extends HandlerThread {
        private RuimRecordsTestHandler(String name) {
            super(name);
        }

        @Override
        public void onLooperPrepared() {
            mRuimRecords = new RuimRecords(mUiccCardApplication3gpp2, mContext, mSimulatedCommands);
            setReady(true);
        }
    }

    @Before
    public void setUp() throws Exception {
        super.setUp(this.getClass().getSimpleName());
        new RuimRecordsTestHandler(TAG).start();
        waitUntilReady();
    }

    @After
    public void tearDown() throws Exception {
        super.tearDown();
    }

    @Test
    public void testCsimImsiLoaded() {
         RuimRecords.EfCsimImsimLoaded mImsiLoaded = mRuimRecords.new EfCsimImsimLoaded();
         AsyncResult ar = new AsyncResult(null, null, null);
         mImsiLoaded.onRecordLoaded(ar);
         String mccmnc = mRuimRecords.getOperatorNumeric();
         assertNull(mccmnc);

         byte[] byteArray = new byte[]{0,19,3,75,68,88,99,(byte)128,(byte)209,0};
         AsyncResult ar2 = new AsyncResult(null, byteArray, null);
         mImsiLoaded.onRecordLoaded(ar2);
         mccmnc = mRuimRecords.getOperatorNumeric();
         assertNotNull(mccmnc);
         assertEquals("31000", mccmnc);
    }
}