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