• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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