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