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(64); 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 cbMessagesDisabledByOem()77 private boolean cbMessagesDisabledByOem() { 78 if (mContext != null && mContext.getResources() != null) { 79 return mContext.getResources().getBoolean( 80 com.android.internal.R.bool.config_disable_all_cb_messages); 81 } else { 82 return false; 83 } 84 } 85 86 /** 87 * Send a GSM CB message to the CellBroadcastServiceManager's handler. 88 * @param m the message 89 */ sendGsmMessageToHandler(Message m)90 public void sendGsmMessageToHandler(Message m) { 91 if (cbMessagesDisabledByOem()) { 92 Log.d(TAG, "GSM CB message ignored - CB messages disabled by OEM."); 93 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_FILTERED, 94 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__TYPE__GSM, 95 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__FILTER__DISABLED_BY_OEM); 96 return; 97 } 98 m.what = EVENT_NEW_GSM_SMS_CB; 99 mModuleCellBroadcastHandler.sendMessage(m); 100 } 101 102 /** 103 * Send a CDMA CB message to the CellBroadcastServiceManager's handler. 104 * @param sms the SmsMessage to forward 105 */ sendCdmaMessageToHandler(SmsMessage sms)106 public void sendCdmaMessageToHandler(SmsMessage sms) { 107 if (cbMessagesDisabledByOem()) { 108 Log.d(TAG, "CDMA CB message ignored - CB messages disabled by OEM."); 109 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_FILTERED, 110 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__TYPE__CDMA, 111 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__FILTER__DISABLED_BY_OEM); 112 return; 113 } 114 Message m = Message.obtain(); 115 m.what = EVENT_NEW_CDMA_SMS_CB; 116 m.obj = sms; 117 mModuleCellBroadcastHandler.sendMessage(m); 118 } 119 120 /** 121 * Send a CDMA Service Category Program message to the CellBroadcastServiceManager's handler. 122 * @param sms the SCP message 123 */ sendCdmaScpMessageToHandler(SmsMessage sms, RemoteCallback callback)124 public void sendCdmaScpMessageToHandler(SmsMessage sms, RemoteCallback callback) { 125 if (cbMessagesDisabledByOem()) { 126 Log.d(TAG, "CDMA SCP CB message ignored - CB messages disabled by OEM."); 127 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_FILTERED, 128 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__TYPE__CDMA_SPC, 129 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__FILTER__DISABLED_BY_OEM); 130 return; 131 } 132 Message m = Message.obtain(); 133 m.what = EVENT_NEW_CDMA_SCP_MESSAGE; 134 m.obj = Pair.create(sms, callback); 135 mModuleCellBroadcastHandler.sendMessage(m); 136 } 137 138 /** 139 * Enable the CB module. The CellBroadcastService will be bound to and CB messages from the 140 * RIL will be forwarded to the module. 141 */ enable()142 public void enable() { 143 initCellBroadcastServiceModule(); 144 } 145 146 /** 147 * Disable the CB module. The manager's handler will no longer receive CB messages from the RIL. 148 */ disable()149 public void disable() { 150 if (mEnabled == false) { 151 return; 152 } 153 mEnabled = false; 154 mPhone.mCi.unSetOnNewGsmBroadcastSms(mModuleCellBroadcastHandler); 155 if (sServiceConnection.mService != null) { 156 mContext.unbindService(sServiceConnection); 157 } 158 } 159 160 /** 161 * The CellBroadcastServiceManager binds to an implementation of the CellBroadcastService 162 * specified in com.android.internal.R.string.cellbroadcast_default_package (typically the 163 * DefaultCellBroadcastService) and forwards cell broadcast messages to the service. 164 */ initCellBroadcastServiceModule()165 private void initCellBroadcastServiceModule() { 166 mEnabled = true; 167 if (sServiceConnection == null) { 168 sServiceConnection = new CellBroadcastServiceConnection(); 169 } 170 mCellBroadcastServicePackage = getCellBroadcastServicePackage(); 171 if (mCellBroadcastServicePackage != null) { 172 mModuleCellBroadcastHandler = new Handler() { 173 @Override 174 public void handleMessage(@NonNull Message msg) { 175 if (!mEnabled) { 176 Log.d(TAG, "CB module is disabled."); 177 return; 178 } 179 if (sServiceConnection.mService == null) { 180 final String errorMessage = "sServiceConnection.mService is null, ignoring message."; 181 Log.d(TAG, errorMessage); 182 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR, 183 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE, 184 errorMessage); 185 return; 186 } 187 try { 188 ICellBroadcastService cellBroadcastService = 189 ICellBroadcastService.Stub.asInterface( 190 sServiceConnection.mService); 191 if (msg.what == EVENT_NEW_GSM_SMS_CB) { 192 mLocalLog.log("GSM SMS CB for phone " + mPhone.getPhoneId()); 193 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_REPORTED, 194 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__TYPE__GSM, 195 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__SOURCE__FRAMEWORK); 196 cellBroadcastService.handleGsmCellBroadcastSms(mPhone.getPhoneId(), 197 (byte[]) ((AsyncResult) msg.obj).result); 198 } else if (msg.what == EVENT_NEW_CDMA_SMS_CB) { 199 mLocalLog.log("CDMA SMS CB for phone " + mPhone.getPhoneId()); 200 SmsMessage sms = (SmsMessage) msg.obj; 201 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_REPORTED, 202 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__TYPE__CDMA, 203 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__SOURCE__FRAMEWORK); 204 cellBroadcastService.handleCdmaCellBroadcastSms(mPhone.getPhoneId(), 205 sms.getEnvelopeBearerData(), sms.getEnvelopeServiceCategory()); 206 } else if (msg.what == EVENT_NEW_CDMA_SCP_MESSAGE) { 207 mLocalLog.log("CDMA SCP message for phone " + mPhone.getPhoneId()); 208 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_REPORTED, 209 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__TYPE__CDMA_SPC, 210 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__SOURCE__FRAMEWORK); 211 Pair<SmsMessage, RemoteCallback> smsAndCallback = 212 (Pair<SmsMessage, RemoteCallback>) msg.obj; 213 SmsMessage sms = smsAndCallback.first; 214 RemoteCallback callback = smsAndCallback.second; 215 cellBroadcastService.handleCdmaScpMessage(mPhone.getPhoneId(), 216 sms.getSmsCbProgramData(), 217 sms.getOriginatingAddress(), 218 callback); 219 } 220 } catch (RemoteException e) { 221 final String errorMessage = "Failed to connect to default app: " 222 + mCellBroadcastServicePackage + " err: " + e.toString(); 223 Log.e(TAG, errorMessage); 224 mLocalLog.log(errorMessage); 225 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR, 226 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE, 227 errorMessage); 228 mContext.unbindService(sServiceConnection); 229 sServiceConnection = null; 230 } 231 } 232 }; 233 234 Intent intent = new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE); 235 intent.setPackage(mCellBroadcastServicePackage); 236 if (sServiceConnection.mService == null) { 237 boolean serviceWasBound = mContext.bindService(intent, sServiceConnection, 238 Context.BIND_AUTO_CREATE); 239 Log.d(TAG, "serviceWasBound=" + serviceWasBound); 240 if (!serviceWasBound) { 241 final String errorMessage = "Unable to bind to service"; 242 Log.e(TAG, errorMessage); 243 mLocalLog.log(errorMessage); 244 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR, 245 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE, 246 errorMessage); 247 return; 248 } 249 } else { 250 Log.d(TAG, "skipping bindService because connection already exists"); 251 } 252 mPhone.mCi.setOnNewGsmBroadcastSms(mModuleCellBroadcastHandler, EVENT_NEW_GSM_SMS_CB, 253 null); 254 } else { 255 final String errorMessage = "Unable to bind service; no cell broadcast service found"; 256 Log.e(TAG, errorMessage); 257 mLocalLog.log(errorMessage); 258 CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR, 259 CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE, 260 errorMessage); 261 } 262 } 263 264 /** Returns the package name of the cell broadcast service, or null if there is none. */ getCellBroadcastServicePackage()265 private String getCellBroadcastServicePackage() { 266 PackageManager packageManager = mContext.getPackageManager(); 267 List<ResolveInfo> cbsPackages = packageManager.queryIntentServices( 268 new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE), 269 PackageManager.MATCH_SYSTEM_ONLY); 270 if (cbsPackages.size() != 1) { 271 Log.e(TAG, "getCellBroadcastServicePackageName: found " + cbsPackages.size() 272 + " CBS packages"); 273 } 274 for (ResolveInfo info : cbsPackages) { 275 if (info.serviceInfo == null) continue; 276 String packageName = info.serviceInfo.packageName; 277 if (!TextUtils.isEmpty(packageName)) { 278 if (packageManager.checkPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE, 279 packageName) == PackageManager.PERMISSION_GRANTED) { 280 Log.d(TAG, "getCellBroadcastServicePackageName: " + packageName); 281 return packageName; 282 } else { 283 Log.e(TAG, "getCellBroadcastServicePackageName: " + packageName 284 + " does not have READ_PRIVILEGED_PHONE_STATE permission"); 285 } 286 } else { 287 Log.e(TAG, "getCellBroadcastServicePackageName: found a CBS package but " 288 + "packageName is null/empty"); 289 } 290 } 291 Log.e(TAG, "getCellBroadcastServicePackageName: package name not found"); 292 return null; 293 } 294 295 private class CellBroadcastServiceConnection implements ServiceConnection { 296 IBinder mService; 297 298 @Override onServiceConnected(ComponentName className, IBinder service)299 public void onServiceConnected(ComponentName className, IBinder service) { 300 Log.d(TAG, "connected to CellBroadcastService"); 301 this.mService = service; 302 } 303 304 @Override onServiceDisconnected(ComponentName arg0)305 public void onServiceDisconnected(ComponentName arg0) { 306 Log.d(TAG, "mICellBroadcastService has disconnected unexpectedly"); 307 this.mService = null; 308 } 309 310 @Override onBindingDied(ComponentName name)311 public void onBindingDied(ComponentName name) { 312 Log.d(TAG, "Binding died"); 313 } 314 315 @Override onNullBinding(ComponentName name)316 public void onNullBinding(ComponentName name) { 317 Log.d(TAG, "Null binding"); 318 } 319 } 320 321 /** 322 * Triggered with `adb shell dumpsys isms` 323 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)324 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 325 pw.println("CellBroadcastServiceManager:"); 326 pw.println(" mEnabled=" + mEnabled); 327 pw.println(" mCellBroadcastServicePackage=" + mCellBroadcastServicePackage); 328 if (mEnabled) { 329 try { 330 if (sServiceConnection != null && sServiceConnection.mService != null) { 331 sServiceConnection.mService.dump(fd, args); 332 } else { 333 pw.println(" sServiceConnection is null"); 334 } 335 } catch (RemoteException e) { 336 pw.println(" mService.dump() threw RemoteException e: " + e.toString()); 337 } 338 } 339 mLocalLog.dump(fd, pw, args); 340 pw.flush(); 341 } 342 } 343