343 lines
15 KiB
Java
343 lines
15 KiB
Java
/*
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.internal.telephony;
|
|
|
|
import android.Manifest;
|
|
import android.annotation.NonNull;
|
|
import android.content.ComponentName;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.ServiceConnection;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.ResolveInfo;
|
|
import android.os.AsyncResult;
|
|
import android.os.Handler;
|
|
import android.os.IBinder;
|
|
import android.os.Message;
|
|
import android.os.RemoteCallback;
|
|
import android.os.RemoteException;
|
|
import android.telephony.CellBroadcastService;
|
|
import android.telephony.ICellBroadcastService;
|
|
import android.text.TextUtils;
|
|
import android.util.LocalLog;
|
|
import android.util.Log;
|
|
import android.util.Pair;
|
|
|
|
import com.android.cellbroadcastservice.CellBroadcastStatsLog;
|
|
import com.android.internal.telephony.cdma.SmsMessage;
|
|
|
|
import java.io.FileDescriptor;
|
|
import java.io.PrintWriter;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Manages a single binding to the CellBroadcastService from the platform. In mSIM cases callers
|
|
* should have one CellBroadcastServiceManager per phone, and the CellBroadcastServiceManager
|
|
* will handle the single binding.
|
|
*/
|
|
public class CellBroadcastServiceManager {
|
|
|
|
private static final String TAG = "CellBroadcastServiceManager";
|
|
|
|
private String mCellBroadcastServicePackage;
|
|
private static CellBroadcastServiceConnection sServiceConnection;
|
|
private Handler mModuleCellBroadcastHandler = null;
|
|
|
|
private Phone mPhone;
|
|
private Context mContext;
|
|
|
|
private final LocalLog mLocalLog = new LocalLog(64);
|
|
|
|
/** New SMS cell broadcast received as an AsyncResult. */
|
|
private static final int EVENT_NEW_GSM_SMS_CB = 0;
|
|
private static final int EVENT_NEW_CDMA_SMS_CB = 1;
|
|
private static final int EVENT_NEW_CDMA_SCP_MESSAGE = 2;
|
|
private boolean mEnabled = false;
|
|
|
|
public CellBroadcastServiceManager(Context context, Phone phone) {
|
|
Log.d(TAG, "CellBroadcastServiceManager created for phone " + phone.getPhoneId());
|
|
mContext = context;
|
|
mPhone = phone;
|
|
}
|
|
|
|
private boolean cbMessagesDisabledByOem() {
|
|
if (mContext != null && mContext.getResources() != null) {
|
|
return mContext.getResources().getBoolean(
|
|
com.android.internal.R.bool.config_disable_all_cb_messages);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send a GSM CB message to the CellBroadcastServiceManager's handler.
|
|
* @param m the message
|
|
*/
|
|
public void sendGsmMessageToHandler(Message m) {
|
|
if (cbMessagesDisabledByOem()) {
|
|
Log.d(TAG, "GSM CB message ignored - CB messages disabled by OEM.");
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_FILTERED,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__TYPE__GSM,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__FILTER__DISABLED_BY_OEM);
|
|
return;
|
|
}
|
|
m.what = EVENT_NEW_GSM_SMS_CB;
|
|
mModuleCellBroadcastHandler.sendMessage(m);
|
|
}
|
|
|
|
/**
|
|
* Send a CDMA CB message to the CellBroadcastServiceManager's handler.
|
|
* @param sms the SmsMessage to forward
|
|
*/
|
|
public void sendCdmaMessageToHandler(SmsMessage sms) {
|
|
if (cbMessagesDisabledByOem()) {
|
|
Log.d(TAG, "CDMA CB message ignored - CB messages disabled by OEM.");
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_FILTERED,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__TYPE__CDMA,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__FILTER__DISABLED_BY_OEM);
|
|
return;
|
|
}
|
|
Message m = Message.obtain();
|
|
m.what = EVENT_NEW_CDMA_SMS_CB;
|
|
m.obj = sms;
|
|
mModuleCellBroadcastHandler.sendMessage(m);
|
|
}
|
|
|
|
/**
|
|
* Send a CDMA Service Category Program message to the CellBroadcastServiceManager's handler.
|
|
* @param sms the SCP message
|
|
*/
|
|
public void sendCdmaScpMessageToHandler(SmsMessage sms, RemoteCallback callback) {
|
|
if (cbMessagesDisabledByOem()) {
|
|
Log.d(TAG, "CDMA SCP CB message ignored - CB messages disabled by OEM.");
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_FILTERED,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__TYPE__CDMA_SPC,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__FILTER__DISABLED_BY_OEM);
|
|
return;
|
|
}
|
|
Message m = Message.obtain();
|
|
m.what = EVENT_NEW_CDMA_SCP_MESSAGE;
|
|
m.obj = Pair.create(sms, callback);
|
|
mModuleCellBroadcastHandler.sendMessage(m);
|
|
}
|
|
|
|
/**
|
|
* Enable the CB module. The CellBroadcastService will be bound to and CB messages from the
|
|
* RIL will be forwarded to the module.
|
|
*/
|
|
public void enable() {
|
|
initCellBroadcastServiceModule();
|
|
}
|
|
|
|
/**
|
|
* Disable the CB module. The manager's handler will no longer receive CB messages from the RIL.
|
|
*/
|
|
public void disable() {
|
|
if (mEnabled == false) {
|
|
return;
|
|
}
|
|
mEnabled = false;
|
|
mPhone.mCi.unSetOnNewGsmBroadcastSms(mModuleCellBroadcastHandler);
|
|
if (sServiceConnection.mService != null) {
|
|
mContext.unbindService(sServiceConnection);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The CellBroadcastServiceManager binds to an implementation of the CellBroadcastService
|
|
* specified in com.android.internal.R.string.cellbroadcast_default_package (typically the
|
|
* DefaultCellBroadcastService) and forwards cell broadcast messages to the service.
|
|
*/
|
|
private void initCellBroadcastServiceModule() {
|
|
mEnabled = true;
|
|
if (sServiceConnection == null) {
|
|
sServiceConnection = new CellBroadcastServiceConnection();
|
|
}
|
|
mCellBroadcastServicePackage = getCellBroadcastServicePackage();
|
|
if (mCellBroadcastServicePackage != null) {
|
|
mModuleCellBroadcastHandler = new Handler() {
|
|
@Override
|
|
public void handleMessage(@NonNull Message msg) {
|
|
if (!mEnabled) {
|
|
Log.d(TAG, "CB module is disabled.");
|
|
return;
|
|
}
|
|
if (sServiceConnection.mService == null) {
|
|
final String errorMessage = "sServiceConnection.mService is null, ignoring message.";
|
|
Log.d(TAG, errorMessage);
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE,
|
|
errorMessage);
|
|
return;
|
|
}
|
|
try {
|
|
ICellBroadcastService cellBroadcastService =
|
|
ICellBroadcastService.Stub.asInterface(
|
|
sServiceConnection.mService);
|
|
if (msg.what == EVENT_NEW_GSM_SMS_CB) {
|
|
mLocalLog.log("GSM SMS CB for phone " + mPhone.getPhoneId());
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_REPORTED,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__TYPE__GSM,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__SOURCE__FRAMEWORK);
|
|
cellBroadcastService.handleGsmCellBroadcastSms(mPhone.getPhoneId(),
|
|
(byte[]) ((AsyncResult) msg.obj).result);
|
|
} else if (msg.what == EVENT_NEW_CDMA_SMS_CB) {
|
|
mLocalLog.log("CDMA SMS CB for phone " + mPhone.getPhoneId());
|
|
SmsMessage sms = (SmsMessage) msg.obj;
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_REPORTED,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__TYPE__CDMA,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__SOURCE__FRAMEWORK);
|
|
cellBroadcastService.handleCdmaCellBroadcastSms(mPhone.getPhoneId(),
|
|
sms.getEnvelopeBearerData(), sms.getEnvelopeServiceCategory());
|
|
} else if (msg.what == EVENT_NEW_CDMA_SCP_MESSAGE) {
|
|
mLocalLog.log("CDMA SCP message for phone " + mPhone.getPhoneId());
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_REPORTED,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__TYPE__CDMA_SPC,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_REPORTED__SOURCE__FRAMEWORK);
|
|
Pair<SmsMessage, RemoteCallback> smsAndCallback =
|
|
(Pair<SmsMessage, RemoteCallback>) msg.obj;
|
|
SmsMessage sms = smsAndCallback.first;
|
|
RemoteCallback callback = smsAndCallback.second;
|
|
cellBroadcastService.handleCdmaScpMessage(mPhone.getPhoneId(),
|
|
sms.getSmsCbProgramData(),
|
|
sms.getOriginatingAddress(),
|
|
callback);
|
|
}
|
|
} catch (RemoteException e) {
|
|
final String errorMessage = "Failed to connect to default app: "
|
|
+ mCellBroadcastServicePackage + " err: " + e.toString();
|
|
Log.e(TAG, errorMessage);
|
|
mLocalLog.log(errorMessage);
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE,
|
|
errorMessage);
|
|
mContext.unbindService(sServiceConnection);
|
|
sServiceConnection = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
Intent intent = new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE);
|
|
intent.setPackage(mCellBroadcastServicePackage);
|
|
if (sServiceConnection.mService == null) {
|
|
boolean serviceWasBound = mContext.bindService(intent, sServiceConnection,
|
|
Context.BIND_AUTO_CREATE);
|
|
Log.d(TAG, "serviceWasBound=" + serviceWasBound);
|
|
if (!serviceWasBound) {
|
|
final String errorMessage = "Unable to bind to service";
|
|
Log.e(TAG, errorMessage);
|
|
mLocalLog.log(errorMessage);
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE,
|
|
errorMessage);
|
|
return;
|
|
}
|
|
} else {
|
|
Log.d(TAG, "skipping bindService because connection already exists");
|
|
}
|
|
mPhone.mCi.setOnNewGsmBroadcastSms(mModuleCellBroadcastHandler, EVENT_NEW_GSM_SMS_CB,
|
|
null);
|
|
} else {
|
|
final String errorMessage = "Unable to bind service; no cell broadcast service found";
|
|
Log.e(TAG, errorMessage);
|
|
mLocalLog.log(errorMessage);
|
|
CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR,
|
|
CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__NO_CONNECTION_TO_CB_SERVICE,
|
|
errorMessage);
|
|
}
|
|
}
|
|
|
|
/** Returns the package name of the cell broadcast service, or null if there is none. */
|
|
private String getCellBroadcastServicePackage() {
|
|
PackageManager packageManager = mContext.getPackageManager();
|
|
List<ResolveInfo> cbsPackages = packageManager.queryIntentServices(
|
|
new Intent(CellBroadcastService.CELL_BROADCAST_SERVICE_INTERFACE),
|
|
PackageManager.MATCH_SYSTEM_ONLY);
|
|
if (cbsPackages.size() != 1) {
|
|
Log.e(TAG, "getCellBroadcastServicePackageName: found " + cbsPackages.size()
|
|
+ " CBS packages");
|
|
}
|
|
for (ResolveInfo info : cbsPackages) {
|
|
if (info.serviceInfo == null) continue;
|
|
String packageName = info.serviceInfo.packageName;
|
|
if (!TextUtils.isEmpty(packageName)) {
|
|
if (packageManager.checkPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|
packageName) == PackageManager.PERMISSION_GRANTED) {
|
|
Log.d(TAG, "getCellBroadcastServicePackageName: " + packageName);
|
|
return packageName;
|
|
} else {
|
|
Log.e(TAG, "getCellBroadcastServicePackageName: " + packageName
|
|
+ " does not have READ_PRIVILEGED_PHONE_STATE permission");
|
|
}
|
|
} else {
|
|
Log.e(TAG, "getCellBroadcastServicePackageName: found a CBS package but "
|
|
+ "packageName is null/empty");
|
|
}
|
|
}
|
|
Log.e(TAG, "getCellBroadcastServicePackageName: package name not found");
|
|
return null;
|
|
}
|
|
|
|
private class CellBroadcastServiceConnection implements ServiceConnection {
|
|
IBinder mService;
|
|
|
|
@Override
|
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
|
Log.d(TAG, "connected to CellBroadcastService");
|
|
this.mService = service;
|
|
}
|
|
|
|
@Override
|
|
public void onServiceDisconnected(ComponentName arg0) {
|
|
Log.d(TAG, "mICellBroadcastService has disconnected unexpectedly");
|
|
this.mService = null;
|
|
}
|
|
|
|
@Override
|
|
public void onBindingDied(ComponentName name) {
|
|
Log.d(TAG, "Binding died");
|
|
}
|
|
|
|
@Override
|
|
public void onNullBinding(ComponentName name) {
|
|
Log.d(TAG, "Null binding");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Triggered with `adb shell dumpsys isms`
|
|
*/
|
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
|
pw.println("CellBroadcastServiceManager:");
|
|
pw.println(" mEnabled=" + mEnabled);
|
|
pw.println(" mCellBroadcastServicePackage=" + mCellBroadcastServicePackage);
|
|
if (mEnabled) {
|
|
try {
|
|
if (sServiceConnection != null && sServiceConnection.mService != null) {
|
|
sServiceConnection.mService.dump(fd, args);
|
|
} else {
|
|
pw.println(" sServiceConnection is null");
|
|
}
|
|
} catch (RemoteException e) {
|
|
pw.println(" mService.dump() threw RemoteException e: " + e.toString());
|
|
}
|
|
}
|
|
mLocalLog.dump(fd, pw, args);
|
|
pw.flush();
|
|
}
|
|
}
|