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

Commit 8bda07c9 authored by Jordan Liu's avatar Jordan Liu Committed by Gerrit Code Review
Browse files

Merge "Handle CMAS messages in CB module"

parents 646e5662 5339ced3
Loading
Loading
Loading
Loading
+44 −6
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ import android.telephony.ICellBroadcastService;
import android.util.LocalLog;
import android.util.Log;

import com.android.internal.telephony.cdma.SmsMessage;

import java.io.FileDescriptor;
import java.io.PrintWriter;

@@ -53,7 +55,8 @@ public class CellBroadcastServiceManager {
    private final LocalLog mLocalLog = new LocalLog(100);

    /** New SMS cell broadcast received as an AsyncResult. */
    private static final int EVENT_NEW_SMS_CB = 0;
    private static final int EVENT_NEW_GSM_SMS_CB = 0;
    private static final int EVENT_NEW_CDMA_SMS_CB = 1;
    private boolean mEnabled;

    public CellBroadcastServiceManager(Context context, Phone phone) {
@@ -63,10 +66,22 @@ public class CellBroadcastServiceManager {
    }

    /**
     * Send a CB message to the CellBroadcastServieManager's handler.
     * Send a GSM CB message to the CellBroadcastServieManager's handler.
     * @param m the message
     */
    public void sendMessageToHandler(Message m) {
    public void sendGsmMessageToHandler(Message m) {
        m.what = EVENT_NEW_GSM_SMS_CB;
        mModuleCellBroadcastHandler.sendMessage(m);
    }

    /**
     * Send a CDMA CB message to the CellBroadcastServieManager's handler.
     * @param sms the SmsMessage to forward
     */
    public void sendCdmaMessageToHandler(SmsMessage sms) {
        Message m = Message.obtain();
        m.what = EVENT_NEW_CDMA_SMS_CB;
        m.obj = sms;
        mModuleCellBroadcastHandler.sendMessage(m);
    }

@@ -106,12 +121,25 @@ public class CellBroadcastServiceManager {
                        Log.d(TAG, "CB module is disabled.");
                        return;
                    }
                    if (sServiceConnection.mService == null) {
                        Log.d(TAG, "No connection to CB module, ignoring message.");
                        return;
                    }
                    try {
                        ICellBroadcastService cellBroadcastService =
                                ICellBroadcastService.Stub.asInterface(
                                        sServiceConnection.mService);
                        if (msg.what == EVENT_NEW_GSM_SMS_CB) {
                            mLocalLog.log("GSM SMS CB for phone " + mPhone.getPhoneId());
                            cellBroadcastService.handleGsmCellBroadcastSms(mPhone.getPhoneId(),
                                    (byte[]) ((AsyncResult) msg.obj).result);
                        } else if (msg.what == EVENT_NEW_CDMA_SMS_CB) {
                            mLocalLog.log("CDMA SMS CB for phone " + mPhone.getPhoneId());
                            SmsMessage sms = (SmsMessage) msg.obj;
                            cellBroadcastService.handleCdmaCellBroadcastSms(mPhone.getPhoneId(),
                                    sms.getEnvelopeBearerData(), sms.getEnvelopeServiceCategory());

                        }
                    } catch (RemoteException e) {
                        Log.e(TAG, "Failed to connect to default app: "
                                + mCellBroadcastServicePackage + " err: " + e.toString());
@@ -128,7 +156,7 @@ public class CellBroadcastServiceManager {
            if (sServiceConnection.mService == null) {
                mContext.bindService(intent, sServiceConnection, Context.BIND_AUTO_CREATE);
            }
            mPhone.mCi.setOnNewGsmBroadcastSms(mModuleCellBroadcastHandler, EVENT_NEW_SMS_CB,
            mPhone.mCi.setOnNewGsmBroadcastSms(mModuleCellBroadcastHandler, EVENT_NEW_GSM_SMS_CB,
                    null);
        } else {
            Log.e(TAG, "Unable to bind service; no cell broadcast service found");
@@ -156,6 +184,16 @@ public class CellBroadcastServiceManager {
            Log.d(TAG, "mICellBroadcastService has disconnected unexpectedly");
            this.mService = null;
        }

        @Override
        public void onBindingDied(ComponentName name) {
            Log.d(TAG, "Binding died");
        }

        @Override
        public void onNullBinding(ComponentName name) {
            Log.d(TAG, "Null binding");
        }
    }

    /**
+77 −0
Original line number Diff line number Diff line
@@ -239,6 +239,10 @@ public abstract class InboundSmsHandler extends StateMachine {
    @UnsupportedAppUsage
    IDeviceIdleController mDeviceIdleController;

    protected static boolean sEnableCbModule = false;

    protected CellBroadcastServiceManager mCellBroadcastServiceManager;

    // Delete permanently from raw table
    private final int DELETE_PERMANENTLY = 1;
    // Only mark deleted, but keep in db for message de-duping
@@ -282,6 +286,7 @@ public abstract class InboundSmsHandler extends StateMachine {
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mDeviceIdleController = TelephonyComponentFactory.getInstance()
                .inject(IDeviceIdleController.class.getName()).getIDeviceIdleController();
        mCellBroadcastServiceManager = new CellBroadcastServiceManager(context, phone);

        addState(mDefaultState);
        addState(mStartupState, mDefaultState);
@@ -306,6 +311,7 @@ public abstract class InboundSmsHandler extends StateMachine {
    @Override
    protected void onQuitting() {
        mWapPush.dispose();
        mCellBroadcastServiceManager.disable();

        while (mWakeLock.isHeld()) {
            mWakeLock.release();
@@ -1701,6 +1707,9 @@ public abstract class InboundSmsHandler extends StateMachine {
        if (mCellBroadcastHandler != null) {
            mCellBroadcastHandler.dump(fd, pw, args);
        }
        if (mCellBroadcastServiceManager != null) {
            mCellBroadcastServiceManager.dump(fd, pw, args);
        }
        mLocalLog.dump(fd, pw, args);
    }

@@ -1745,6 +1754,32 @@ public abstract class InboundSmsHandler extends StateMachine {
        }
    }

    protected byte[] decodeHexString(String hexString) {
        if (hexString == null || hexString.length() % 2 == 1) {
            return null;
        }
        byte[] bytes = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
        }
        return bytes;
    }

    private byte hexToByte(String hexString) {
        int firstDigit = toDigit(hexString.charAt(0));
        int secondDigit = toDigit(hexString.charAt(1));
        return (byte) ((firstDigit << 4) + secondDigit);
    }

    private int toDigit(char hexChar) {
        int digit = Character.digit(hexChar, 16);
        if (digit == -1) {
            return 0;
        }
        return digit;
    }


    /**
     * Registers the broadcast receiver to launch the default SMS app when the user clicks the
     * new message notification.
@@ -1754,4 +1789,46 @@ public abstract class InboundSmsHandler extends StateMachine {
        userFilter.addAction(ACTION_OPEN_SMS_APP);
        context.registerReceiver(new NewMessageNotificationActionReceiver(), userFilter);
    }

    protected abstract class CbTestBroadcastReceiver extends BroadcastReceiver {

        protected abstract void handleTestAction(Intent intent);
        protected abstract void handleToggleEnable();
        protected abstract void handleToggleDisable(Context context);

        protected final String mTestAction;
        protected final String mToggleAction;

        public CbTestBroadcastReceiver(String testAction, String toggleAction) {
            mTestAction = testAction;
            mToggleAction = toggleAction;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            logd("Received test intent action=" + intent.getAction());
            if (intent.getAction().equals(mTestAction)) {
                // Return early if phone_id is explicilty included and does not match mPhone.
                // If phone_id extra is not included, continue.
                int phoneId = mPhone.getPhoneId();
                if (intent.getIntExtra("phone_id", phoneId) != phoneId) {
                    return;
                }
                handleTestAction(intent);
            } else if (intent.getAction().equals(mToggleAction)) {
                if (intent.hasExtra("enable")) {
                    sEnableCbModule = intent.getBooleanExtra("enable", false);
                } else {
                    sEnableCbModule = !sEnableCbModule;
                }
                if (sEnableCbModule) {
                    log("enabling CB module");
                    handleToggleEnable();
                } else {
                    log("enabling legacy platform CB handling");
                    handleToggleDisable(context);
                }
            }
        }
    }
}
+111 −6
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.internal.telephony.cdma;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.os.Message;
import android.provider.Telephony.Sms.Intents;
@@ -34,6 +36,7 @@ import com.android.internal.telephony.SmsMessageBase;
import com.android.internal.telephony.SmsStorageMonitor;
import com.android.internal.telephony.TelephonyComponentFactory;
import com.android.internal.telephony.WspTypeDecoder;
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
import com.android.internal.util.HexDump;

@@ -46,6 +49,7 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler {

    private final CdmaSMSDispatcher mSmsDispatcher;
    private final CdmaServiceCategoryProgramHandler mServiceCategoryProgramHandler;
    private static CdmaCbTestBroadcastReceiver sTestBroadcastReceiver;

    private byte[] mLastDispatchedSmsFingerprint;
    private byte[] mLastAcknowledgedSmsFingerprint;
@@ -53,6 +57,15 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler {
    private final boolean mCheckForDuplicatePortsInOmadmWapPush = Resources.getSystem().getBoolean(
            com.android.internal.R.bool.config_duplicate_port_omadm_wappush);

    // When TEST_MODE is on we allow the test intent to trigger an SMS CB alert
    private static boolean sEnableCbModule = false;
    private static final boolean TEST_MODE = true; //STOPSHIP if true
    private static final String TEST_ACTION = "com.android.internal.telephony.cdma"
            + ".TEST_TRIGGER_CELL_BROADCAST";
    private static final String TOGGLE_CB_MODULE = "com.android.internal.telephony.cdma"
            + ".TOGGLE_CB_MODULE";


    /**
     * Create a new inbound SMS handler for CDMA.
     */
@@ -64,6 +77,17 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler {
        mServiceCategoryProgramHandler = CdmaServiceCategoryProgramHandler.makeScpHandler(context,
                phone.mCi);
        phone.mCi.setOnNewCdmaSms(getHandler(), EVENT_NEW_SMS, null);

        mCellBroadcastServiceManager.enable();
        if (TEST_MODE) {
            if (sTestBroadcastReceiver == null) {
                sTestBroadcastReceiver = new CdmaCbTestBroadcastReceiver();
                IntentFilter filter = new IntentFilter();
                filter.addAction(TEST_ACTION);
                filter.addAction(TOGGLE_CB_MODULE);
                context.registerReceiver(sTestBroadcastReceiver, filter);
            }
        }
    }

    /**
@@ -111,13 +135,10 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler {
        // Handle CMAS emergency broadcast messages.
        if (isBroadcastType) {
            log("Broadcast type message");
            String plmn =
                    TelephonyManager.from(mContext).getNetworkOperatorForPhone(mPhone.getPhoneId());
            SmsCbMessage cbMessage = sms.parseBroadcastSms(plmn, mPhone.getPhoneId());
            if (cbMessage != null) {
                mCellBroadcastHandler.dispatchSmsMessage(cbMessage);
            if (sEnableCbModule) {
                mCellBroadcastServiceManager.sendCdmaMessageToHandler(sms);
            } else {
                loge("error trying to parse broadcast SMS");
                legacyDispatchSmsCbMessage(sms);
            }
            return Intents.RESULT_SMS_HANDLED;
        }
@@ -184,6 +205,19 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler {
        return dispatchNormalMessage(smsb);
    }

    // dispatch an SMS message through the platform
    private void legacyDispatchSmsCbMessage(SmsMessage sms) {
        String plmn =
                TelephonyManager.from(mContext).getNetworkOperatorForPhone(
                        mPhone.getPhoneId());
        SmsCbMessage cbMessage = sms.parseBroadcastSms(plmn, mPhone.getPhoneId());
        if (cbMessage != null) {
            mCellBroadcastHandler.dispatchSmsMessage(cbMessage);
        } else {
            loge("error trying to parse broadcast SMS");
        }
    }

    /**
     * Send an acknowledge message.
     * @param success indicates that last message was successfully received.
@@ -349,4 +383,75 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler {
        mMetrics.writeIncomingVoiceMailSms(mPhone.getPhoneId(),
                android.telephony.SmsMessage.FORMAT_3GPP2);
    }

    /**
     * A broadcast receiver used for testing emergency cell broadcasts. To trigger test CDMA cell
     * broadcasts with adb run e.g:
     *
     * adb shell am broadcast -a com.android.internal.telephony.cdma.TEST_TRIGGER_CELL_BROADCAST \
     * --ei service_category 4097 \
     * --es bearer_data_string 00031303900801C00D0101015C02D00002BFD1931054D208119313D3D10815D05 \
     * 493925391C81193D48814D3D555120810D3D0D3D3925393C810D3D5539516480B481393D495120810D1539514 \
     * 9053081054925693D390481553951253080D0C4D481413481354D500
     *
     * adb shell am broadcast -a com.android.internal.telephony.cdma.TEST_TRIGGER_CELL_BROADCAST \
     * --ei service_category 4097 \
     * --es bearer_data_string 00031303900801C00D0101015C02D00002BFD1931054D208119313D3D10815D05 \
     * 493925391C81193D48814D3D555120810D3D0D3D3925393C810D3D5539516480B481393D495120810D1539514 \
     * 9053081054925693D390481553951253080D0C4D481413481354D500 \
     * --ei phone_id 0 \
     *
     * adb shell am broadcast -a com.android.internal.telephony.cdma.TOGGLE_CB_MODULE
     *
     * adb shell am broadcast -a com.android.internal.telephony.cdma.TOGGLE_CB_MODULE \
     * --ez enable true
     */
    private class CdmaCbTestBroadcastReceiver extends CbTestBroadcastReceiver {

        CdmaCbTestBroadcastReceiver() {
            super(TEST_ACTION, TOGGLE_CB_MODULE);
        }

        @Override
        protected void handleTestAction(Intent intent) {
            SmsEnvelope envelope = new SmsEnvelope();
            // the CdmaSmsAddress is not used for a test cell broadcast message, but needs to be
            // supplied to avoid a null pointer exception in the platform
            CdmaSmsAddress nonNullAddress = new CdmaSmsAddress();
            nonNullAddress.origBytes = new byte[] { (byte) 0xFF };
            envelope.origAddress = nonNullAddress;

            // parse service category from intent
            envelope.serviceCategory = intent.getIntExtra("service_category", -1);
            if (envelope.serviceCategory == -1) {
                log("No service category, ignoring CB test intent");
                return;
            }

            // parse bearer data from intent
            String bearerDataString = intent.getStringExtra("bearer_data_string");
            envelope.bearerData = decodeHexString(bearerDataString);
            if (envelope.bearerData == null) {
                log("No bearer data, ignoring CB test intent");
                return;
            }

            SmsMessage sms = new SmsMessage(new CdmaSmsAddress(), envelope);
            if (sEnableCbModule) {
                mCellBroadcastServiceManager.sendCdmaMessageToHandler(sms);
            } else {
                legacyDispatchSmsCbMessage(sms);
            }
        }

        @Override
        protected void handleToggleEnable() {
            // sEnableCbModule is already toggled in super class
        }

        @Override
        protected void handleToggleDisable(Context context) {
            // sEnableCbModule is already toggled in super class
        }
    }
}
+52 −91
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import android.os.AsyncResult;
import android.os.Message;
import android.provider.Telephony.Sms.Intents;

import com.android.internal.telephony.CellBroadcastServiceManager;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.InboundSmsHandler;
import com.android.internal.telephony.Phone;
@@ -36,9 +35,6 @@ import com.android.internal.telephony.SmsStorageMonitor;
import com.android.internal.telephony.VisualVoicemailSmsFilter;
import com.android.internal.telephony.uicc.UsimServiceTable;

import java.io.FileDescriptor;
import java.io.PrintWriter;

/**
 * This class broadcasts incoming SMS messages to interested apps after storing them in
 * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been
@@ -50,13 +46,11 @@ public class GsmInboundSmsHandler extends InboundSmsHandler {
    private final UsimDataDownloadHandler mDataDownloadHandler;

    // When TEST_MODE is on we allow the test intent to trigger an SMS CB alert
    private static boolean sEnableCbModule = false;
    private static final boolean TEST_MODE = true; //STOPSHIP if true
    private static final String TEST_ACTION = "com.android.internal.telephony.gsm"
            + ".TEST_TRIGGER_CELL_BROADCAST";
    private static final String TOGGLE_CB_MODULE = "com.android.internal.telephony.gsm"
            + ".TOGGLE_CB_MODULE";
    private CellBroadcastServiceManager mCellBroadcastServiceManager;

    /**
     * Create a new GSM inbound SMS handler.
@@ -66,7 +60,6 @@ public class GsmInboundSmsHandler extends InboundSmsHandler {
        super("GsmInboundSmsHandler", context, storageMonitor, phone, null);
        phone.mCi.setOnNewGsmSms(getHandler(), EVENT_NEW_SMS, null);
        mDataDownloadHandler = new UsimDataDownloadHandler(phone.mCi, phone.getPhoneId());
        mCellBroadcastServiceManager = new CellBroadcastServiceManager(context, phone);
        if (sEnableCbModule) {
            mCellBroadcastServiceManager.enable();
        } else {
@@ -75,6 +68,7 @@ public class GsmInboundSmsHandler extends InboundSmsHandler {
        }

        if (TEST_MODE) {
            if (sTestBroadcastReceiver == null) {
                sTestBroadcastReceiver = new GsmCbTestBroadcastReceiver();
                IntentFilter filter = new IntentFilter();
                filter.addAction(TEST_ACTION);
@@ -82,6 +76,7 @@ public class GsmInboundSmsHandler extends InboundSmsHandler {
                context.registerReceiver(sTestBroadcastReceiver, filter);
            }
        }
    }


    /**
@@ -100,13 +95,17 @@ public class GsmInboundSmsHandler extends InboundSmsHandler {
     *
     * adb shell am broadcast -a com.android.internal.telephony.gsm.TOGGLE_CB_MODULE
     *
     * adb shell am broadcast -a com.android.internal.telephony.gsm.TOGGLE_CB_MODULE -ez enable true
     * adb shell am broadcast -a com.android.internal.telephony.gsm.TOGGLE_CB_MODULE \
     * --ez enable true
     */
    private class GsmCbTestBroadcastReceiver extends BroadcastReceiver {
    private class GsmCbTestBroadcastReceiver extends CbTestBroadcastReceiver {

        GsmCbTestBroadcastReceiver() {
            super(TEST_ACTION, TOGGLE_CB_MODULE);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            logd("Received test intent action=" + intent.getAction());
            if (intent.getAction() == TEST_ACTION) {
        protected void handleTestAction(Intent intent) {
            byte[] smsPdu = intent.getByteArrayExtra("pdu");
            if (smsPdu == null) {
                String pduString = intent.getStringExtra("pdu_string");
@@ -126,23 +125,21 @@ public class GsmInboundSmsHandler extends InboundSmsHandler {
            Message m = Message.obtain();
            AsyncResult.forMessage(m, smsPdu, null);
            if (sEnableCbModule) {
                    mCellBroadcastServiceManager.sendMessageToHandler(m);
                mCellBroadcastServiceManager.sendGsmMessageToHandler(m);
            } else {
                m.setWhat(GsmCellBroadcastHandler.EVENT_NEW_SMS_MESSAGE);
                mCellBroadcastHandler.sendMessage(m);
            }
            } else if (intent.getAction() == TOGGLE_CB_MODULE) {
                if (intent.hasExtra("enable")) {
                    sEnableCbModule = intent.getBooleanExtra("enable", false);
                } else {
                    sEnableCbModule = !sEnableCbModule;
        }
                if (sEnableCbModule) {
                    log("enabling CB module");

        @Override
        protected void handleToggleEnable() {
            mPhone.mCi.unSetOnNewGsmBroadcastSms(mCellBroadcastHandler.getHandler());
            mCellBroadcastServiceManager.enable();
                } else {
                    log("enabling legacy platform CB handling");
        }

        @Override
        protected void handleToggleDisable(Context context) {
            mCellBroadcastServiceManager.disable();
            if (mCellBroadcastHandler == null) {
                mCellBroadcastHandler =
@@ -153,33 +150,6 @@ public class GsmInboundSmsHandler extends InboundSmsHandler {
                    GsmCellBroadcastHandler.EVENT_NEW_SMS_MESSAGE, null);
        }
    }
        }
    }

    private byte[] decodeHexString(String hexString) {
        if (hexString == null || hexString.length() % 2 == 1) {
            return null;
        }
        byte[] bytes = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
        }
        return bytes;
    }

    private byte hexToByte(String hexString) {
        int firstDigit = toDigit(hexString.charAt(0));
        int secondDigit = toDigit(hexString.charAt(1));
        return (byte) ((firstDigit << 4) + secondDigit);
    }

    private int toDigit(char hexChar) {
        int digit = Character.digit(hexChar, 16);
        if (digit == -1) {
            return 0;
        }
        return digit;
    }

    /**
     * Unregister for GSM SMS.
@@ -187,7 +157,6 @@ public class GsmInboundSmsHandler extends InboundSmsHandler {
    @Override
    protected void onQuitting() {
        mPhone.mCi.unSetOnNewGsmSms(getHandler());
        mCellBroadcastServiceManager.disable();
        mCellBroadcastHandler.dispose();

        if (DBG) log("unregistered for 3GPP SMS");
@@ -335,12 +304,4 @@ public class GsmInboundSmsHandler extends InboundSmsHandler {
        mMetrics.writeIncomingVoiceMailSms(mPhone.getPhoneId(),
                android.telephony.SmsMessage.FORMAT_3GPP);
    }

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        super.dump(fd, pw, args);
        if (mCellBroadcastServiceManager != null) {
            mCellBroadcastServiceManager.dump(fd, pw, args);
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -807,7 +807,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {

        // verify that a broadcast receiver is registered for current user (user == null) based on
        // implementation in ContextFixture
        verify(mContext, times(2)).registerReceiverAsUser(any(BroadcastReceiver.class),
        verify(mContext, times(1)).registerReceiverAsUser(any(BroadcastReceiver.class),
                eq((UserHandle)null), any(IntentFilter.class), eq((String)null), eq((Handler)null));

        // wait for ScanRawTableThread