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