1 /*
2  * Copyright (C) 2011 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.cellbroadcastreceiver;
18 
19 import static com.android.cellbroadcastreceiver.CellBroadcastReceiver.VDBG;
20 
21 import android.app.IntentService;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.SharedPreferences;
25 import android.content.res.Resources;
26 import android.preference.PreferenceManager;
27 import android.telephony.SmsManager;
28 import android.telephony.SubscriptionInfo;
29 import android.telephony.SubscriptionManager;
30 import android.util.Log;
31 
32 import androidx.annotation.NonNull;
33 
34 import com.android.cellbroadcastreceiver.CellBroadcastChannelManager.CellBroadcastChannelRange;
35 import com.android.internal.annotations.VisibleForTesting;
36 
37 import java.lang.reflect.Method;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 
42 /**
43  * This service manages enabling and disabling ranges of message identifiers
44  * that the radio should listen for. It operates independently of the other
45  * services and runs at boot time and after exiting airplane mode.
46  *
47  * Note that the entire range of emergency channels is enabled. Test messages
48  * and lower priority broadcasts are filtered out in CellBroadcastAlertService
49  * if the user has not enabled them in settings.
50  *
51  * TODO: add notification to re-enable channels after a radio reset.
52  */
53 public class CellBroadcastConfigService extends IntentService {
54     private static final String TAG = "CellBroadcastConfigService";
55 
56     @VisibleForTesting
57     public static final String ACTION_ENABLE_CHANNELS = "ACTION_ENABLE_CHANNELS";
58 
CellBroadcastConfigService()59     public CellBroadcastConfigService() {
60         super(TAG);          // use class name for worker thread name
61     }
62 
63     @Override
onHandleIntent(Intent intent)64     protected void onHandleIntent(Intent intent) {
65         if (ACTION_ENABLE_CHANNELS.equals(intent.getAction())) {
66             try {
67                 SubscriptionManager subManager = (SubscriptionManager) getApplicationContext()
68                         .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
69 
70                 if (subManager != null) {
71                     // Retrieve all the active subscription indice and enable cell broadcast
72                     // messages on all subs. The duplication detection will be done at the
73                     // frameworks.
74                     int[] subIds = getActiveSubIdList(subManager);
75                     if (subIds.length != 0) {
76                         for (int subId : subIds) {
77                             log("Enable CellBroadcast on sub " + subId);
78                             enableCellBroadcastChannels(subId);
79                         }
80                     } else {
81                         // For no sim scenario.
82                         enableCellBroadcastChannels(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
83                     }
84                 }
85             } catch (Exception ex) {
86                 Log.e(TAG, "exception enabling cell broadcast channels", ex);
87             }
88         }
89     }
90 
91     @NonNull
getActiveSubIdList(SubscriptionManager subMgr)92     private int[] getActiveSubIdList(SubscriptionManager subMgr) {
93         List<SubscriptionInfo> subInfos = subMgr.getActiveSubscriptionInfoList();
94         int size = subInfos != null ? subInfos.size() : 0;
95         int[] subIds = new int[size];
96         for (int i = 0; i < size; i++) {
97             subIds[i] = subInfos.get(i).getSubscriptionId();
98         }
99         return subIds;
100     }
101 
resetCellBroadcastChannels(int subId)102     private void resetCellBroadcastChannels(int subId) {
103         SmsManager manager;
104         if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
105             manager = SmsManager.getSmsManagerForSubscriptionId(subId);
106         } else {
107             manager = SmsManager.getDefault();
108         }
109 
110         // TODO: Call manager.resetAllCellBroadcastRanges() in Android S.
111         try {
112             Method method = SmsManager.class.getDeclaredMethod("resetAllCellBroadcastRanges");
113             method.invoke(manager);
114         } catch (Exception e) {
115             log("Can't reset cell broadcast ranges. e=" + e);
116         }
117     }
118 
119     /**
120      * Enable cell broadcast messages channels. Messages can be only received on the
121      * enabled channels.
122      *
123      * @param subId Subscription index
124      */
125     @VisibleForTesting
enableCellBroadcastChannels(int subId)126     public void enableCellBroadcastChannels(int subId) {
127         resetCellBroadcastChannels(subId);
128 
129         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
130         Resources res = CellBroadcastSettings.getResources(this, subId);
131 
132         // boolean for each user preference checkbox, true for checked, false for unchecked
133         // Note: If enableAlertsMasterToggle is false, it disables ALL emergency broadcasts
134         // except for CMAS presidential. i.e. to receive CMAS severe alerts, both
135         // enableAlertsMasterToggle AND enableCmasSevereAlerts must be true.
136         boolean enableAlertsMasterToggle = prefs.getBoolean(
137                 CellBroadcastSettings.KEY_ENABLE_ALERTS_MASTER_TOGGLE, true);
138 
139         boolean enableEtwsAlerts = enableAlertsMasterToggle;
140 
141         // CMAS Presidential must be always on (See 3GPP TS 22.268 Section 6.2) regardless
142         // user's preference
143         boolean enablePresidential = true;
144 
145         boolean enableCmasExtremeAlerts = enableAlertsMasterToggle && prefs.getBoolean(
146                 CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, true);
147 
148         boolean enableCmasSevereAlerts = enableAlertsMasterToggle && prefs.getBoolean(
149                 CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, true);
150 
151         boolean enableCmasAmberAlerts = enableAlertsMasterToggle && prefs.getBoolean(
152                 CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, true);
153 
154         boolean enableTestAlerts = enableAlertsMasterToggle
155                 && CellBroadcastSettings.isTestAlertsToggleVisible(getApplicationContext())
156                 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, false);
157 
158         boolean enableAreaUpdateInfoAlerts = res.getBoolean(
159                 R.bool.config_showAreaUpdateInfoSettings)
160                 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_AREA_UPDATE_INFO_ALERTS,
161                 false);
162 
163         boolean enablePublicSafetyMessagesChannelAlerts = enableAlertsMasterToggle
164                 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_PUBLIC_SAFETY_MESSAGES,
165                 true);
166         boolean enableStateLocalTestAlerts = enableAlertsMasterToggle
167                 && prefs.getBoolean(CellBroadcastSettings.KEY_ENABLE_STATE_LOCAL_TEST_ALERTS,
168                 false);
169 
170         boolean enableEmergencyAlerts = enableAlertsMasterToggle && prefs.getBoolean(
171                 CellBroadcastSettings.KEY_ENABLE_EMERGENCY_ALERTS, true);
172 
173         boolean enableGeoFencingTriggerMessage = true;
174 
175         if (VDBG) {
176             log("enableAlertsMasterToggle = " + enableAlertsMasterToggle);
177             log("enableEtwsAlerts = " + enableEtwsAlerts);
178             log("enablePresidential = " + enablePresidential);
179             log("enableCmasExtremeAlerts = " + enableCmasExtremeAlerts);
180             log("enableCmasSevereAlerts = " + enableCmasExtremeAlerts);
181             log("enableCmasAmberAlerts = " + enableCmasAmberAlerts);
182             log("enableTestAlerts = " + enableTestAlerts);
183             log("enableAreaUpdateInfoAlerts = " + enableAreaUpdateInfoAlerts);
184             log("enablePublicSafetyMessagesChannelAlerts = "
185                     + enablePublicSafetyMessagesChannelAlerts);
186             log("enableStateLocalTestAlerts = " + enableStateLocalTestAlerts);
187             log("enableEmergencyAlerts = " + enableEmergencyAlerts);
188             log("enableGeoFencingTriggerMessage = " + enableGeoFencingTriggerMessage);
189         }
190 
191         CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(
192                 getApplicationContext(), subId);
193 
194         /** Enable CMAS series messages. */
195 
196         // Enable/Disable Presidential messages.
197         setCellBroadcastRange(subId, enablePresidential,
198                 channelManager.getCellBroadcastChannelRanges(
199                         R.array.cmas_presidential_alerts_channels_range_strings));
200 
201         // Enable/Disable CMAS extreme messages.
202         setCellBroadcastRange(subId, enableCmasExtremeAlerts,
203                 channelManager.getCellBroadcastChannelRanges(
204                         R.array.cmas_alert_extreme_channels_range_strings));
205 
206         // Enable/Disable CMAS severe messages.
207         setCellBroadcastRange(subId, enableCmasSevereAlerts,
208                 channelManager.getCellBroadcastChannelRanges(
209                         R.array.cmas_alerts_severe_range_strings));
210 
211         // Enable/Disable CMAS amber alert messages.
212         setCellBroadcastRange(subId, enableCmasAmberAlerts,
213                 channelManager.getCellBroadcastChannelRanges(
214                         R.array.cmas_amber_alerts_channels_range_strings));
215 
216         // Enable/Disable test messages.
217         setCellBroadcastRange(subId, enableTestAlerts,
218                 channelManager.getCellBroadcastChannelRanges(
219                         R.array.required_monthly_test_range_strings));
220 
221         // Exercise is part of test toggle with monthly test and operator defined. some carriers
222         // mandate to show test settings in UI but always enable exercise alert.
223         setCellBroadcastRange(subId, enableTestAlerts ||
224                         res.getBoolean(R.bool.always_enable_exercise_alert),
225                 channelManager.getCellBroadcastChannelRanges(
226                         R.array.exercise_alert_range_strings));
227 
228         setCellBroadcastRange(subId, enableTestAlerts,
229                 channelManager.getCellBroadcastChannelRanges(
230                         R.array.operator_defined_alert_range_strings));
231 
232         // Enable/Disable GSM ETWS messages.
233         setCellBroadcastRange(subId, enableEtwsAlerts,
234                 channelManager.getCellBroadcastChannelRanges(
235                         R.array.etws_alerts_range_strings));
236 
237         // Enable/Disable GSM ETWS test messages.
238         setCellBroadcastRange(subId, enableTestAlerts,
239                 channelManager.getCellBroadcastChannelRanges(
240                         R.array.etws_test_alerts_range_strings));
241 
242         // Enable/Disable GSM public safety messages.
243         setCellBroadcastRange(subId, enablePublicSafetyMessagesChannelAlerts,
244                 channelManager.getCellBroadcastChannelRanges(
245                         R.array.public_safety_messages_channels_range_strings));
246 
247         // Enable/Disable GSM state/local test alerts.
248         setCellBroadcastRange(subId, enableStateLocalTestAlerts,
249                 channelManager.getCellBroadcastChannelRanges(
250                         R.array.state_local_test_alert_range_strings));
251 
252         // Enable/Disable GSM geo-fencing trigger messages.
253         setCellBroadcastRange(subId, enableGeoFencingTriggerMessage,
254                 channelManager.getCellBroadcastChannelRanges(
255                         R.array.geo_fencing_trigger_messages_range_strings));
256 
257         // Enable non-CMAS series messages.
258         setCellBroadcastRange(subId, enableEmergencyAlerts,
259                 channelManager.getCellBroadcastChannelRanges(
260                         R.array.emergency_alerts_channels_range_strings));
261 
262         // Enable/Disable additional channels based on carrier specific requirement.
263         ArrayList<CellBroadcastChannelRange> ranges =
264                 channelManager.getCellBroadcastChannelRanges(
265                         R.array.additional_cbs_channels_strings);
266 
267         for (CellBroadcastChannelRange range: ranges) {
268             boolean enableAlerts;
269             switch (range.mAlertType) {
270                 case AREA:
271                     enableAlerts = enableAreaUpdateInfoAlerts;
272                     break;
273                 case TEST:
274                     enableAlerts = enableTestAlerts;
275                     break;
276                 default:
277                     enableAlerts = enableAlertsMasterToggle;
278             }
279             setCellBroadcastRange(subId, enableAlerts, new ArrayList<>(Arrays.asList(range)));
280         }
281     }
282     /**
283      * Enable/disable cell broadcast with messages id range
284      * @param subId Subscription index
285      * @param enable True for enabling cell broadcast with id range, otherwise for disabling.
286      * @param ranges Cell broadcast id ranges
287      */
setCellBroadcastRange(int subId, boolean enable, List<CellBroadcastChannelRange> ranges)288     private void setCellBroadcastRange(int subId, boolean enable,
289                                        List<CellBroadcastChannelRange> ranges) {
290         SmsManager manager;
291         if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
292             manager = SmsManager.getSmsManagerForSubscriptionId(subId);
293         } else {
294             manager = SmsManager.getDefault();
295         }
296 
297         if (ranges != null) {
298             for (CellBroadcastChannelRange range: ranges) {
299                 if (enable) {
300                     manager.enableCellBroadcastRange(range.mStartId, range.mEndId, range.mRanType);
301                 } else {
302                     manager.disableCellBroadcastRange(range.mStartId, range.mEndId, range.mRanType);
303                 }
304             }
305         }
306     }
307 
log(String msg)308     private static void log(String msg) {
309         Log.d(TAG, msg);
310     }
311 }
312