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

Commit bcba292e authored by android-build-team Robot's avatar android-build-team Robot
Browse files

release-request-99856c15-b008-4977-9971-f86523a23c0a-for-git_oc-m2-release-436...

release-request-99856c15-b008-4977-9971-f86523a23c0a-for-git_oc-m2-release-4367109 snap-temp-L18300000107415568

Change-Id: I76df70a8b46ef37e43fca666f6f94da8d3c6d5d4
parents fa27857a 289b7251
Loading
Loading
Loading
Loading
+87 −38
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.util.Pair;

import com.android.internal.annotations.VisibleForTesting;

@@ -44,10 +45,14 @@ import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;

/**
@@ -68,16 +73,16 @@ public class CarrierKeyDownloadManager {
    private static final String INTENT_KEY_RENEWAL_ALARM_PREFIX =
            "com.android.internal.telephony.carrier_key_download_alarm";

    private int mKeyAvailability = 0;
    @VisibleForTesting
    public int mKeyAvailability = 0;

    public static final String MNC = "MNC";
    public static final String MCC = "MCC";
    private static final String SEPARATOR = ":";

    private static final String JSON_KEY = "key";
    private static final String JSON_CERTIFICATE = "certificate";
    private static final String JSON_TYPE = "type";
    private static final String JSON_IDENTIFIER = "identifier";
    private static final String JSON_EXPIRATION_DATE = "expiration-date";
    private static final String JSON_CARRIER_KEYS = "carrier-keys";
    private static final String JSON_TYPE_VALUE_WLAN = "WLAN";
    private static final String JSON_TYPE_VALUE_EPDG = "EPDG";
@@ -89,7 +94,7 @@ public class CarrierKeyDownloadManager {

    private final Phone mPhone;
    private final Context mContext;
    private final DownloadManager mDownloadManager;
    public final DownloadManager mDownloadManager;
    private String mURL;

    public CarrierKeyDownloadManager(Phone phone) {
@@ -173,14 +178,11 @@ public class CarrierKeyDownloadManager {
    }

    /**
     * this method resets the alarm. Starts by cleaning up the existing alarms.
     * We look at the earliest expiration date, and setup an alarms X days prior.
     * If the expiration date is in the past, we'll setup an alarm to run the next day. This
     * could happen if the download has failed.
     * this method returns the date to be used to decide on when to start downloading the key.
     * from the carrier.
     **/
    private void resetRenewalAlarm() {
        cleanupRenewalAlarms();
        int slotId = mPhone.getPhoneId();
    @VisibleForTesting
    public long getExpirationDate()  {
        long minExpirationDate = Long.MAX_VALUE;
        for (int key_type : CARRIER_KEY_TYPES) {
            if (!isKeyEnabled(key_type)) {
@@ -204,6 +206,20 @@ public class CarrierKeyDownloadManager {
        } else {
            minExpirationDate = minExpirationDate - DEFAULT_RENEWAL_WINDOW_DAYS * DAY_IN_MILLIS;
        }
        return minExpirationDate;
    }

    /**
     * this method resets the alarm. Starts by cleaning up the existing alarms.
     * We look at the earliest expiration date, and setup an alarms X days prior.
     * If the expiration date is in the past, we'll setup an alarm to run the next day. This
     * could happen if the download has failed.
     **/
    @VisibleForTesting
    public void resetRenewalAlarm() {
        cleanupRenewalAlarms();
        int slotId = mPhone.getPhoneId();
        long minExpirationDate = getExpirationDate();
        Log.d(LOG_TAG, "minExpirationDate: " + new Date(minExpirationDate));
        final AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
                Context.ALARM_SERVICE);
@@ -224,22 +240,31 @@ public class CarrierKeyDownloadManager {
        return preferences.getString(MCC_MNC_PREF_TAG + slotId, null);
    }

    /**
     * Returns the sim operator.
     **/
    @VisibleForTesting
    public String getSimOperator() {
        final TelephonyManager telephonyManager =
                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        return telephonyManager.getSimOperator(mPhone.getSubId());
    }

    /**
     *  checks if the download was sent by this particular instance. We do this by including the
     *  slot id in the key. If no value is found, we know that the download was not for this
     *  instance of the phone.
     **/
    private boolean isValidDownload(String mccMnc) {
    @VisibleForTesting
    public boolean isValidDownload(String mccMnc) {
        String mccCurrent = "";
        String mncCurrent = "";
        String mccSource = "";
        String mncSource = "";
        final TelephonyManager telephonyManager =
                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        String networkOperator = telephonyManager.getNetworkOperator(mPhone.getSubId());

        if (TextUtils.isEmpty(networkOperator) || TextUtils.isEmpty(mccMnc)) {
            Log.e(LOG_TAG, "networkOperator or mcc/mnc is empty");
        String simOperator = getSimOperator();
        if (TextUtils.isEmpty(simOperator) || TextUtils.isEmpty(mccMnc)) {
            Log.e(LOG_TAG, "simOperator or mcc/mnc is empty");
            return false;
        }

@@ -248,8 +273,8 @@ public class CarrierKeyDownloadManager {
        mncSource = splitValue[1];
        Log.d(LOG_TAG, "values from sharedPrefs mcc, mnc: " + mccSource + "," + mncSource);

        mccCurrent = networkOperator.substring(0, 3);
        mncCurrent = networkOperator.substring(3);
        mccCurrent = simOperator.substring(0, 3);
        mncCurrent = simOperator.substring(3);
        Log.d(LOG_TAG, "using values for mcc, mnc: " + mccCurrent + "," + mncCurrent);

        if (TextUtils.equals(mncSource, mncCurrent) &&  TextUtils.equals(mccSource, mccCurrent)) {
@@ -349,14 +374,14 @@ public class CarrierKeyDownloadManager {
     * including the Carrier public key, the key type and the key identifier. Once the nodes have
     * been extracted, they get persisted to the database. Sample:
     *      "carrier-keys": [ { "key": "",
     *                         "type": WLAN,
     *                         "identifier": "",
     *                         "expiration-date": 1502577746000
     *                         "type": "WLAN",
     *                         "identifier": ""
     *                        } ]
     * @param jsonStr the json string.
     * @param mccMnc contains the mcc, mnc
     */
    private void parseJsonAndPersistKey(String jsonStr, String mccMnc) {
    @VisibleForTesting
    public void parseJsonAndPersistKey(String jsonStr, String mccMnc) {
        if (TextUtils.isEmpty(jsonStr) || TextUtils.isEmpty(mccMnc)) {
            Log.e(LOG_TAG, "jsonStr or mcc, mnc: is empty");
            return;
@@ -372,7 +397,7 @@ public class CarrierKeyDownloadManager {

            for (int i = 0; i < keys.length(); i++) {
                JSONObject key = keys.getJSONObject(i);
                String carrierKey = key.getString(JSON_KEY);
                String cert = key.getString(JSON_CERTIFICATE);
                String typeString = key.getString(JSON_TYPE);
                int type = UNINITIALIZED_KEY_TYPE;
                if (typeString.equals(JSON_TYPE_VALUE_WLAN)) {
@@ -380,13 +405,14 @@ public class CarrierKeyDownloadManager {
                } else if (typeString.equals(JSON_TYPE_VALUE_EPDG)) {
                    type = TelephonyManager.KEY_TYPE_EPDG;
                }
                long expiration_date = key.getLong(JSON_EXPIRATION_DATE);
                String identifier = key.getString(JSON_IDENTIFIER);
                savePublicKey(carrierKey, type, identifier, expiration_date,
                        mcc, mnc);
                Pair<PublicKey, Long> keyInfo = getKeyInformation(cert);
                savePublicKey(keyInfo.first, type, identifier, keyInfo.second, mcc, mnc);
            }
        } catch (final JSONException e) {
            Log.e(LOG_TAG, "Json parsing error: " + e.getMessage());
        } catch (final Exception e) {
            Log.e(LOG_TAG, "Exception getting certificate: " + e);
        }
    }

@@ -394,8 +420,8 @@ public class CarrierKeyDownloadManager {
     * introspects the mKeyAvailability bitmask
     * @return true if the digit at position k is 1, else false.
     */

    private boolean isKeyEnabled(int keyType) {
    @VisibleForTesting
    public boolean isKeyEnabled(int keyType) {
        //since keytype has values of 1, 2.... we need to subtract 1 from the keytype.
        int returnValue = (mKeyAvailability >> (keyType - 1)) & 1;
        return (returnValue == 1) ? true : false;
@@ -427,15 +453,13 @@ public class CarrierKeyDownloadManager {

    private boolean downloadKey() {
        Log.d(LOG_TAG, "starting download from: " + mURL);
        final TelephonyManager telephonyManager =
                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        String mcc = "";
        String mnc = "";
        String networkOperator = telephonyManager.getNetworkOperator(mPhone.getSubId());
        String simOperator = getSimOperator();

        if (!TextUtils.isEmpty(networkOperator)) {
            mcc = networkOperator.substring(0, 3);
            mnc = networkOperator.substring(3);
        if (!TextUtils.isEmpty(simOperator)) {
            mcc = simOperator.substring(0, 3);
            mnc = simOperator.substring(3);
            Log.d(LOG_TAG, "using values for mcc, mnc: " + mcc + "," + mnc);
        } else {
            Log.e(LOG_TAG, "mcc, mnc: is empty");
@@ -461,11 +485,36 @@ public class CarrierKeyDownloadManager {
        return true;
    }

    private void savePublicKey(String key, int type, String identifier, long expirationDate,
    /**
     * Save the public key
     * @param certificate certificate that contains the public key.
     * @return Pair containing the Public Key and the expiration date.
     **/
    @VisibleForTesting
    public static Pair<PublicKey, Long> getKeyInformation(String certificate) throws Exception {
        byte[] derCert = Base64.decode(certificate.getBytes(), Base64.DEFAULT);
        InputStream inStream = new ByteArrayInputStream(derCert);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
        Pair<PublicKey, Long> keyInformation =
                new Pair(cert.getPublicKey(), cert.getNotAfter().getTime());
        return keyInformation;
    }

    /**
     * Save the public key
     * @param publicKey public key.
     * @param type key-type.
     * @param identifier which is an opaque string.
     * @param expirationDate expiration date of the key.
     * @param mcc
     * @param mnc
     **/
    @VisibleForTesting
    public void savePublicKey(PublicKey publicKey, int type, String identifier, long expirationDate,
                               String mcc, String mnc) {
        byte[] keyBytes = Base64.decode(key.getBytes(), Base64.DEFAULT);
        ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo(mcc, mnc, type, identifier,
                keyBytes, new Date(expirationDate));
                publicKey, new Date(expirationDate));
        mPhone.setCarrierInfoForImsiEncryption(imsiEncryptionInfo);
    }
}
+47 −0
Original line number Diff line number Diff line
@@ -158,6 +158,17 @@ public abstract class InboundSmsHandler extends StateMachine {
    /** New SMS received as an AsyncResult. */
    public static final int EVENT_INJECT_SMS = 8;

    /** Update tracker object; used only in waiting state */
    private static final int EVENT_UPDATE_TRACKER = 9;

    /** Timeout in case state machine is stuck in a state for too long; used only in waiting
     * state */
    private static final int EVENT_STATE_TIMEOUT = 10;

    /** Timeout duration for EVENT_STATE_TIMEOUT */
    @VisibleForTesting
    public static final int STATE_TIMEOUT = 30000;

    /** Wakelock release delay when returning to idle state. */
    private static final int WAKELOCK_TIMEOUT = 3000;

@@ -450,6 +461,7 @@ public abstract class InboundSmsHandler extends StateMachine {
                    // if any broadcasts were sent, transition to waiting state
                    InboundSmsTracker inboundSmsTracker = (InboundSmsTracker) msg.obj;
                    if (processMessagePart(inboundSmsTracker)) {
                        sendMessage(EVENT_UPDATE_TRACKER, inboundSmsTracker);
                        transitionTo(mWaitingState);
                    } else {
                        // if event is sent from SmsBroadcastUndelivered.broadcastSms(), and
@@ -493,18 +505,41 @@ public abstract class InboundSmsHandler extends StateMachine {
     * {@link IdleState} after any deferred {@link #EVENT_BROADCAST_SMS} messages are handled.
     */
    private class WaitingState extends State {
        private InboundSmsTracker mTracker;

        @Override
        public void enter() {
            if (DBG) log("entering Waiting state");
            mTracker = null;
            sendMessageDelayed(EVENT_STATE_TIMEOUT, STATE_TIMEOUT);
        }

        @Override
        public void exit() {
            if (DBG) log("exiting Waiting state");
            // Before moving to idle state, set wakelock timeout to WAKE_LOCK_TIMEOUT milliseconds
            // to give any receivers time to take their own wake locks
            setWakeLockTimeout(WAKELOCK_TIMEOUT);
            if (VDBG) {
                if (hasMessages(EVENT_STATE_TIMEOUT)) {
                    log("exiting Waiting state: removing EVENT_STATE_TIMEOUT from message queue");
                }
                if (hasMessages(EVENT_UPDATE_TRACKER)) {
                    log("exiting Waiting state: removing EVENT_UPDATE_TRACKER from message queue");
                }
            }
            removeMessages(EVENT_STATE_TIMEOUT);
            removeMessages(EVENT_UPDATE_TRACKER);
        }

        @Override
        public boolean processMessage(Message msg) {
            log("WaitingState.processMessage:" + msg.what);
            switch (msg.what) {
                case EVENT_UPDATE_TRACKER:
                    mTracker = (InboundSmsTracker) msg.obj;
                    return HANDLED;

                case EVENT_BROADCAST_SMS:
                    // defer until the current broadcast completes
                    deferMessage(msg);
@@ -520,6 +555,18 @@ public abstract class InboundSmsHandler extends StateMachine {
                    // not ready to return to idle; ignore
                    return HANDLED;

                case EVENT_STATE_TIMEOUT:
                    // stuck in WaitingState for too long; drop the message and exit this state
                    if (mTracker != null) {
                        log("WaitingState.processMessage: EVENT_STATE_TIMEOUT; dropping message");
                        dropSms(new SmsBroadcastReceiver(mTracker));
                    } else {
                        log("WaitingState.processMessage: EVENT_STATE_TIMEOUT; mTracker is null "
                                + "- sending EVENT_BROADCAST_COMPLETE");
                        sendMessage(EVENT_BROADCAST_COMPLETE);
                    }
                    return HANDLED;

                default:
                    // parent state handles the other message types
                    return NOT_HANDLED;
+284 −0

File added.

Preview size limit exceeded, changes collapsed.

+4 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.when;

import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.DownloadManager;
import android.app.NotificationManager;
import android.app.usage.UsageStatsManager;
import android.content.BroadcastReceiver;
@@ -240,6 +241,8 @@ public class ContextFixture implements TestFixture<Context> {
                    return mEuiccManager;
                case Context.TELECOM_SERVICE:
                    return mTelecomManager;
                case Context.DOWNLOAD_SERVICE:
                    return mDownloadManager;
                case Context.DISPLAY_SERVICE:
                case Context.POWER_SERVICE:
                    // PowerManager and DisplayManager are final classes so cannot be mocked,
@@ -496,6 +499,7 @@ public class ContextFixture implements TestFixture<Context> {
    private final Resources mResources = mock(Resources.class);
    private final PackageManager mPackageManager = mock(PackageManager.class);
    private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
    private final DownloadManager mDownloadManager = mock(DownloadManager.class);
    private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class);
    private final NotificationManager mNotificationManager = mock(NotificationManager.class);
    private final UserManager mUserManager = mock(UserManager.class);
+25 −1
Original line number Diff line number Diff line
@@ -47,8 +47,8 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Telephony;
import android.support.test.filters.FlakyTest;
import android.support.test.filters.MediumTest;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.MediumTest;

import com.android.internal.telephony.FakeSmsContentProvider;
import com.android.internal.telephony.InboundSmsHandler;
@@ -781,4 +781,28 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {

        verifySmsIntentBroadcasts(0);
    }

    @FlakyTest
    @Ignore
    @Test
    @MediumTest
    public void testWaitingStateTimeout() throws Exception {
        transitionFromStartupToIdle();

        // send new SMS to state machine and verify that triggers SMS_DELIVER_ACTION
        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS,
                new AsyncResult(null, mSmsMessage, null));
        waitForMs(100);

        ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
        verify(mContext, times(1)).sendBroadcast(
                intentArgumentCaptor.capture());
        assertEquals(Telephony.Sms.Intents.SMS_DELIVER_ACTION,
                intentArgumentCaptor.getAllValues().get(0).getAction());
        assertEquals("WaitingState", getCurrentState().getName());

        waitForMs(InboundSmsHandler.STATE_TIMEOUT + 300);

        assertEquals("IdleState", getCurrentState().getName());
    }
}