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