1 /* 2 * Copyright (C) 2019 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 17 package com.android.cellbroadcastservice; 18 19 import static com.android.cellbroadcastservice.CellBroadcastMetrics.ERR_CDMA_DECODING; 20 import static com.android.cellbroadcastservice.CellBroadcastMetrics.RPT_CDMA; 21 import static com.android.cellbroadcastservice.CellBroadcastMetrics.SRC_CBS; 22 23 import android.annotation.NonNull; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.os.Bundle; 27 import android.provider.Telephony; 28 import android.telephony.CellBroadcastService; 29 import android.telephony.SmsCbLocation; 30 import android.telephony.SmsCbMessage; 31 import android.telephony.SubscriptionManager; 32 import android.telephony.TelephonyManager; 33 import android.telephony.cdma.CdmaSmsCbProgramData; 34 import android.util.Log; 35 36 import com.android.internal.annotations.VisibleForTesting; 37 38 import java.io.FileDescriptor; 39 import java.io.PrintWriter; 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.function.Consumer; 43 44 /** 45 * The default implementation of CellBroadcastService, which is used for handling GSM and CDMA cell 46 * broadcast messages. 47 */ 48 public class DefaultCellBroadcastService extends CellBroadcastService { 49 private GsmCellBroadcastHandler mGsmCellBroadcastHandler; 50 private CellBroadcastHandler mCdmaCellBroadcastHandler; 51 private CdmaServiceCategoryProgramHandler mCdmaScpHandler; 52 53 private static final String TAG = "DefaultCellBroadcastService"; 54 55 private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', 56 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 57 58 @Override onCreate()59 public void onCreate() { 60 super.onCreate(); 61 mGsmCellBroadcastHandler = 62 GsmCellBroadcastHandler.makeGsmCellBroadcastHandler(getApplicationContext()); 63 mCdmaCellBroadcastHandler = 64 CellBroadcastHandler.makeCellBroadcastHandler(getApplicationContext()); 65 mCdmaScpHandler = 66 CdmaServiceCategoryProgramHandler.makeScpHandler(getApplicationContext()); 67 } 68 69 @Override onDestroy()70 public void onDestroy() { 71 mGsmCellBroadcastHandler.cleanup(); 72 mCdmaCellBroadcastHandler.cleanup(); 73 super.onDestroy(); 74 } 75 76 @Override onGsmCellBroadcastSms(int slotIndex, byte[] message)77 public void onGsmCellBroadcastSms(int slotIndex, byte[] message) { 78 Log.d(TAG, "onGsmCellBroadcastSms received message on slotId=" + slotIndex); 79 mGsmCellBroadcastHandler.onGsmCellBroadcastSms(slotIndex, message); 80 } 81 82 @Override onCdmaCellBroadcastSms(int slotIndex, byte[] bearerData, int serviceCategory)83 public void onCdmaCellBroadcastSms(int slotIndex, byte[] bearerData, int serviceCategory) { 84 Log.d(TAG, "onCdmaCellBroadcastSms received message on slotId=" + slotIndex); 85 86 int subId = CellBroadcastHandler.getSubIdForPhone(getApplicationContext(), slotIndex); 87 88 String plmn = ""; 89 if (SubscriptionManager.isValidSubscriptionId(subId)) { 90 plmn = getSystemService(TelephonyManager.class) 91 .createForSubscriptionId(subId).getNetworkOperator(); 92 } 93 94 SmsCbMessage message = parseCdmaBroadcastSms(getApplicationContext(), slotIndex, plmn, 95 bearerData, serviceCategory); 96 if (message != null) { 97 CellBroadcastServiceMetrics.getInstance().logMessageReported(getApplicationContext(), 98 RPT_CDMA, SRC_CBS, message.getSerialNumber(), message.getServiceCategory()); 99 mCdmaCellBroadcastHandler.onCdmaCellBroadcastSms(message); 100 } 101 } 102 103 @Override onCdmaScpMessage(int slotIndex, List<CdmaSmsCbProgramData> programData, String originatingAddress, Consumer<Bundle> callback)104 public void onCdmaScpMessage(int slotIndex, List<CdmaSmsCbProgramData> programData, 105 String originatingAddress, Consumer<Bundle> callback) { 106 Log.d(TAG, "onCdmaScpMessage received message on slotId=" + slotIndex); 107 mCdmaScpHandler.onCdmaScpMessage(slotIndex, new ArrayList<>(programData), 108 originatingAddress, callback); 109 } 110 111 @Override getCellBroadcastAreaInfo(int slotIndex)112 public @NonNull String getCellBroadcastAreaInfo(int slotIndex) { 113 Log.d(TAG, "getCellBroadcastAreaInfo on slotId=" + slotIndex); 114 return mGsmCellBroadcastHandler.getCellBroadcastAreaInfo(slotIndex); 115 } 116 117 /** 118 * Parses a CDMA broadcast SMS 119 * 120 * @param slotIndex the slotIndex the SMS was received on 121 * @param plmn the PLMN for a broadcast SMS or "" if unknown 122 * @param bearerData the bearerData of the SMS 123 * @param serviceCategory the service category of the broadcast 124 */ 125 @VisibleForTesting parseCdmaBroadcastSms(Context context, int slotIndex, String plmn, byte[] bearerData, int serviceCategory)126 public static SmsCbMessage parseCdmaBroadcastSms(Context context, int slotIndex, String plmn, 127 byte[] bearerData, 128 int serviceCategory) { 129 BearerData bData; 130 try { 131 bData = BearerData.decode(context, bearerData, serviceCategory); 132 } catch (Exception e) { 133 final String errorMessage = "Error decoding bearer data e=" + e.toString(); 134 Log.e(TAG, errorMessage); 135 CellBroadcastServiceMetrics.getInstance() 136 .logMessageError(ERR_CDMA_DECODING, errorMessage); 137 return null; 138 } 139 Log.d(TAG, "MT raw BearerData = " + toHexString(bearerData, 0, bearerData.length)); 140 SmsCbLocation location = new SmsCbLocation(plmn, -1, -1); 141 142 int subId = CellBroadcastHandler.getSubIdForPhone(context, slotIndex); 143 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 144 subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 145 } 146 147 return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP2, 148 SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE, bData.messageId, location, 149 serviceCategory, bData.getLanguage(), bData.userData.msgEncoding, 150 bData.userData.payloadStr, bData.priority, null, bData.cmasWarningInfo, 0, null, 151 System.currentTimeMillis(), slotIndex, subId); 152 } 153 toHexString(byte[] array, int offset, int length)154 private static String toHexString(byte[] array, int offset, int length) { 155 char[] buf = new char[length * 2]; 156 int bufIndex = 0; 157 for (int i = offset; i < offset + length; i++) { 158 byte b = array[i]; 159 buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; 160 buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; 161 } 162 return new String(buf); 163 } 164 165 @Override dump(FileDescriptor fd, PrintWriter writer, String[] args)166 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 167 writer.println("DefaultCellBroadcastService:"); 168 Intent intent = new Intent(Telephony.Sms.Intents.ACTION_SMS_EMERGENCY_CB_RECEIVED); 169 writer.println( 170 " defaultCBRPackageName=" + GsmCellBroadcastHandler.getDefaultCBRPackageName( 171 getApplicationContext(), intent)); 172 if (mGsmCellBroadcastHandler != null) { 173 mGsmCellBroadcastHandler.dump(fd, writer, args); 174 } else { 175 writer.println(" mGsmCellBroadcastHandler is null"); 176 } 177 if (mCdmaCellBroadcastHandler != null) { 178 mCdmaCellBroadcastHandler.dump(fd, writer, args); 179 } else { 180 writer.println(" mCdmaCellBroadcastHandler is null"); 181 } 182 if (mCdmaScpHandler != null) { 183 mCdmaScpHandler.dump(fd, writer, args); 184 } else { 185 writer.println(" mCdmaScpHandler is null"); 186 } 187 } 188 } 189