• 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.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