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

Commit 1d699982 authored by Jordan Liu's avatar Jordan Liu Committed by android-build-merger
Browse files

Merge "Handle CMAS messages in CB module" am: 8bda07c9

am: fe401354

Change-Id: I8b144862d4f5401dc33f87f3739f79ce01579271
parents a9e79a51 fe401354
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
@@ -240,6 +240,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
@@ -283,6 +287,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);
@@ -307,6 +312,7 @@ public abstract class InboundSmsHandler extends StateMachine {
    @Override
    protected void onQuitting() {
        mWapPush.dispose();
        mCellBroadcastServiceManager.disable();

        while (mWakeLock.isHeld()) {
            mWakeLock.release();
@@ -1702,6 +1708,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);
    }

@@ -1746,6 +1755,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.
@@ -1755,4 +1790,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