• 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.internal.telephony;
18 
19 import android.Manifest;
20 import android.annotation.NonNull;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.content.pm.PackageManager;
26 import android.content.pm.ResolveInfo;
27 import android.os.AsyncResult;
28 import android.os.Handler;
29 import android.os.IBinder;
30 import android.os.Message;
31 import android.os.RemoteCallback;
32 import android.os.RemoteException;
33 import android.telephony.CellBroadcastService;
34 import android.telephony.ICellBroadcastService;
35 import android.text.TextUtils;
36 import android.util.LocalLog;
37 import android.util.Log;
38 import android.util.Pair;
39 
40 import com.android.cellbroadcastservice.CellBroadcastStatsLog;
41 import com.android.internal.telephony.cdma.SmsMessage;
42 
43 import java.io.FileDescriptor;
44 import java.io.PrintWriter;
45 import java.util.List;
46 
47 /**
48  * Manages a single binding to the CellBroadcastService from the platform. In mSIM cases callers
49  * should have one CellBroadcastServiceManager per phone, and the CellBroadcastServiceManager
50  * will handle the single binding.
51  */
52 public class CellBroadcastServiceManager {
53 
54     private static final String TAG = "CellBroadcastServiceManager";
55 
56     private String mCellBroadcastServicePackage;
57     private static CellBroadcastServiceConnection sServiceConnection;
58     private Handler mModuleCellBroadcastHandler = null;
59 
60     private Phone mPhone;
61     private Context mContext;
62 
63     private final LocalLog mLocalLog = new LocalLog(100);
64 
65     /** New SMS cell broadcast received as an AsyncResult. */
66     private static final int EVENT_NEW_GSM_SMS_CB = 0;
67     private static final int EVENT_NEW_CDMA_SMS_CB = 1;
68     private static final int EVENT_NEW_CDMA_SCP_MESSAGE = 2;
69     private boolean mEnabled = false;
70 
CellBroadcastServiceManager(Context context, Phone phone)71     public CellBroadcastServiceManager(Context context, Phone phone) {
72         Log.d(TAG, "CellBroadcastServiceManager created for phone " + phone.getPhoneId());
73         mContext = context;
74         mPhone = phone;
75     }
76 
77     /**
78      * Send a GSM CB message to the CellBroadcastServiceManager's handler.
79      * @param m the message
80      */
sendGsmMessageToHandler(Message m)81     public void sendGsmMessageToHandler(Message m) {
82         m.what = EVENT_NEW_GSM_SMS_CB;
83         mModuleCellBroadcastHandler.sendMessage(m);
84     }
85 
86     /**
87      * Send a CDMA CB message to the CellBroadcastServiceManager's handler.
88      * @param sms the SmsMessage to forward
89      */
sendCdmaMessageToHandler(SmsMessage sms)90     public void sendCdmaMessageToHandler(SmsMessage sms) {
91         Message m = Message.obtain();
92         m.what = EVENT_NEW_CDMA_SMS_CB;
93         m.obj = sms;
94         mModuleCellBroadcastHandler.sendMessage(m);
95     }
96 
97     /**
98      * Send a CDMA Service Category Program message to the CellBroadcastServiceManager's handler.
99      * @param sms the SCP message
100      */
sendCdmaScpMessageToHandler(SmsMessage sms, RemoteCallback callback)101     public void sendCdmaScpMessageToHandler(SmsMessage sms, RemoteCallback callback) {
102         Message m = Message.obtain();
103         m.what = EVENT_NEW_CDMA_SCP_MESSAGE;
104         m.obj = Pair.create(sms, callback);
105         mModuleCellBroadcastHandler.sendMessage(m);
106     }
107 
108     /**
109      * Enable the CB module. The CellBroadcastService will be bound to and CB messages from the
110      * RIL will be forwarded to the module.
111      */
enable()112     public void enable() {
113         initCellBroadcastServiceModule();
114     }
115 
116     /**
117      * Disable the CB module. The manager's handler will no longer receive CB messages from the RIL.
118      */
disable()119     public void disable() {
120         if (mEnabled == false) {
121             return;
122         }
123         mEnabled = false;
124         mPhone.mCi.unSetOnNewGsmBroadcastSms(mModuleCellBroadcastHandler);
125         if (sServiceConnection.mService != null) {
126             mContext.unbindService(sServiceConnection);
127         }
128     }
129 
130     /**
131      * The CellBroadcastServiceManager binds to an implementation of the CellBroadcastService
132      * specified in com.android.internal.R.string.cellbroadcast_default_package (typically the
133      * DefaultCellBroadcastService) and forwards cell broadcast messages to the service.
134      */
initCellBroadcastServiceModule()135     private void initCellBroadcastServiceModule() {
136         mEnabled = true;
137         if (sServiceConnection == null) {
138             sServiceConnection = new CellBroadcastServiceConnection();
139         }
140         mCellBroadcastServicePackage = getCellBroadcastServicePackage();
141         if (mCellBroadcastServicePackage != null) {
142             mModuleCellBroadcastHandler = new Handler() {
143                 @Override
144                 public void handleMessage(@NonNull Message msg) {
145                     if (!mEnabled) {
146                         Log.d(TAG, "CB module is disabled.");
147                         return;
148                     }
149                     if (sServiceConnection.mService == null) {
150                         final String errorMessage = "sServiceConnection.mService is null, ignoring message.";
151                         Log.d(TAG, errorMessage);
152                         CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR,
153                                 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE,
154                                 errorMessage);
155                         return;
156                     }
157                     try {
158                         ICellBroadcastService cellBroadcastService =
159                                 ICellBroadcastService.Stub.asInterface(
160                                         sServiceConnection.mService);
161                         if (msg.what == EVENT_NEW_GSM_SMS_CB) {
162                             mLocalLog.log("GSM SMS CB for phone " + mPhone.getPhoneId());
163                             CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_REPORTED,
164                                     CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__TYPE__GSM,
165                                     CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__SOURCE__FRAMEWORK);
166                             cellBroadcastService.handleGsmCellBroadcastSms(mPhone.getPhoneId(),
167                                     (byte[]) ((AsyncResult) msg.obj).result);
168                         } else if (msg.what == EVENT_NEW_CDMA_SMS_CB) {
169                             mLocalLog.log("CDMA SMS CB for phone " + mPhone.getPhoneId());
170                             SmsMessage sms = (SmsMessage) msg.obj;
171                             CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_REPORTED,
172                                     CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__TYPE__CDMA,
173                                     CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__SOURCE__FRAMEWORK);
174                             cellBroadcastService.handleCdmaCellBroadcastSms(mPhone.getPhoneId(),
175                                     sms.getEnvelopeBearerData(), sms.getEnvelopeServiceCategory());
176                         } else if (msg.what == EVENT_NEW_CDMA_SCP_MESSAGE) {
177                             mLocalLog.log("CDMA SCP message for phone " + mPhone.getPhoneId());
178                             CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_REPORTED,
179                                     CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__TYPE__CDMA_SPC,
180                                     CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__SOURCE__FRAMEWORK);
181                             Pair<SmsMessage, RemoteCallback> smsAndCallback =
182                                     (Pair<SmsMessage, RemoteCallback>) msg.obj;
183                             SmsMessage sms = smsAndCallback.first;
184                             RemoteCallback callback = smsAndCallback.second;
185                             cellBroadcastService.handleCdmaScpMessage(mPhone.getPhoneId(),
186                                     sms.getSmsCbProgramData(),
187                                     sms.getOriginatingAddress(),
188                                     callback);
189                         }
190                     } catch (RemoteException e) {
191                         final String errorMessage = "Failed to connect to default app: "
192                                 + mCellBroadcastServicePackage + " err: " + e.toString();
193                         Log.e(TAG, errorMessage);
194                         mLocalLog.log(errorMessage);
195                         CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR,
196                                 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE,
197                                 errorMessage);
198                         mContext.unbindService(sServiceConnection);
199                         sServiceConnection = null;
200                     }
201                 }
202             };
203 
204             Intent intent = new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE);
205             intent.setPackage(mCellBroadcastServicePackage);
206             if (sServiceConnection.mService == null) {
207                 boolean serviceWasBound = mContext.bindService(intent, sServiceConnection,
208                         Context.BIND_AUTO_CREATE);
209                 Log.d(TAG, "serviceWasBound=" + serviceWasBound);
210                 if (!serviceWasBound) {
211                     final String errorMessage = "Unable to bind to service";
212                     Log.e(TAG, errorMessage);
213                     mLocalLog.log(errorMessage);
214                     CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR,
215                             CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE,
216                             errorMessage);
217                     return;
218                 }
219             } else {
220                 Log.d(TAG, "skipping bindService because connection already exists");
221             }
222             mPhone.mCi.setOnNewGsmBroadcastSms(mModuleCellBroadcastHandler, EVENT_NEW_GSM_SMS_CB,
223                     null);
224         } else {
225             final String errorMessage = "Unable to bind service; no cell broadcast service found";
226             Log.e(TAG, errorMessage);
227             mLocalLog.log(errorMessage);
228             CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR,
229                     CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE,
230                     errorMessage);
231         }
232     }
233 
234     /** Returns the package name of the cell broadcast service, or null if there is none. */
getCellBroadcastServicePackage()235     private String getCellBroadcastServicePackage() {
236         PackageManager packageManager = mContext.getPackageManager();
237         List<ResolveInfo> cbsPackages = packageManager.queryIntentServices(
238                 new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE),
239                 PackageManager.MATCH_SYSTEM_ONLY);
240         if (cbsPackages.size() != 1) {
241             Log.e(TAG, "getCellBroadcastServicePackageName: found " + cbsPackages.size()
242                     + " CBS packages");
243         }
244         for (ResolveInfo info : cbsPackages) {
245             if (info.serviceInfo == null) continue;
246             String packageName = info.serviceInfo.packageName;
247             if (!TextUtils.isEmpty(packageName)) {
248                 if (packageManager.checkPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
249                         packageName) == PackageManager.PERMISSION_GRANTED) {
250                     Log.d(TAG, "getCellBroadcastServicePackageName: " + packageName);
251                     return packageName;
252                 } else {
253                     Log.e(TAG, "getCellBroadcastServicePackageName: " + packageName
254                             + " does not have READ_PRIVILEGED_PHONE_STATE permission");
255                 }
256             } else {
257                 Log.e(TAG, "getCellBroadcastServicePackageName: found a CBS package but "
258                         + "packageName is null/empty");
259             }
260         }
261         Log.e(TAG, "getCellBroadcastServicePackageName: package name not found");
262         return null;
263     }
264 
265     private class CellBroadcastServiceConnection implements ServiceConnection {
266         IBinder mService;
267 
268         @Override
onServiceConnected(ComponentName className, IBinder service)269         public void onServiceConnected(ComponentName className, IBinder service) {
270             Log.d(TAG, "connected to CellBroadcastService");
271             this.mService = service;
272         }
273 
274         @Override
onServiceDisconnected(ComponentName arg0)275         public void onServiceDisconnected(ComponentName arg0) {
276             Log.d(TAG, "mICellBroadcastService has disconnected unexpectedly");
277             this.mService = null;
278         }
279 
280         @Override
onBindingDied(ComponentName name)281         public void onBindingDied(ComponentName name) {
282             Log.d(TAG, "Binding died");
283         }
284 
285         @Override
onNullBinding(ComponentName name)286         public void onNullBinding(ComponentName name) {
287             Log.d(TAG, "Null binding");
288         }
289     }
290 
291     /**
292      * Triggered with `adb shell dumpsys isms`
293      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)294     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
295         pw.println("CellBroadcastServiceManager:");
296         pw.println(" mEnabled=" + mEnabled);
297         pw.println(" mCellBroadcastServicePackage=" + mCellBroadcastServicePackage);
298         mLocalLog.dump(fd, pw, args);
299         pw.flush();
300     }
301 }
302