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