Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 38e206b9 authored by Hayden Gomes's avatar Hayden Gomes Committed by android-build-merger
Browse files

Merge changes from topic "SMS over Bluetooth" am: 96ab9b0a

am: 0bccddbf

Change-Id: I909e47190a0f22c405f81f207148ee1f1561daf7
parents 1e5db488 0bccddbf
Loading
Loading
Loading
Loading
+121 −0
Original line number Diff line number Diff line
/*
 * 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.app.ActivityThread;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothProfile;
import android.net.Uri;
import android.telecom.PhoneAccount;
import android.telephony.SmsManager;
import android.telephony.SubscriptionInfo;
import android.util.Log;


/**
 * BtSmsInterfaceManager to provide a mechanism for sending SMS over Bluetooth
 */
public class BtSmsInterfaceManager {

    private static final String LOG_TAG = "BtSmsInterfaceManager";

    /**
     * Sends text through connected Bluetooth device
     */
    public void sendText(String destAddr, String text, PendingIntent sentIntent,
            PendingIntent deliveryIntent, SubscriptionInfo info) {
        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
        if (btAdapter == null) {
            // No bluetooth service on this platform?
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
            return;
        }
        BluetoothDevice device = btAdapter.getRemoteDevice(info.getIccId());
        if (device == null) {
            Log.d(LOG_TAG, "Bluetooth device addr invalid: " + info.getIccId());
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
            return;
        }
        btAdapter.getProfileProxy(ActivityThread.currentApplication().getApplicationContext(),
                new MapMessageSender(destAddr, text, device, sentIntent, deliveryIntent),
                BluetoothProfile.MAP_CLIENT);
    }

    private void sendErrorInPendingIntent(PendingIntent intent, int errorCode) {
        if (intent == null) {
            return;
        }
        try {
            intent.send(errorCode);
        } catch (PendingIntent.CanceledException e) {
            // PendingIntent is cancelled. ignore sending this error code back to
            // caller.
            Log.d(LOG_TAG, "PendingIntent.CanceledException: " + e.getMessage());
        }
    }

    private class MapMessageSender implements BluetoothProfile.ServiceListener {

        final Uri[] mDestAddr;
        private String mMessage;
        final BluetoothDevice mDevice;
        final PendingIntent mSentIntent;
        final PendingIntent mDeliveryIntent;

        MapMessageSender(final String destAddr, final String message, final BluetoothDevice device,
                final PendingIntent sentIntent, final PendingIntent deliveryIntent) {
            super();
            mDestAddr = new Uri[]{new Uri.Builder()
                    .appendPath(destAddr)
                    .scheme(PhoneAccount.SCHEME_TEL)
                    .build()};
            mMessage = message;
            mDevice = device;
            mSentIntent = sentIntent;
            mDeliveryIntent = deliveryIntent;
        }

        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            Log.d(LOG_TAG, "Service connected");
            if (profile != BluetoothProfile.MAP_CLIENT) {
                return;
            }
            BluetoothMapClient mapProfile = (BluetoothMapClient) proxy;
            if (mMessage != null) {
                Log.d(LOG_TAG, "Sending message thru bluetooth");
                mapProfile.sendMessage(mDevice, mDestAddr, mMessage, mSentIntent, mDeliveryIntent);
                mMessage = null;
            }
            BluetoothAdapter.getDefaultAdapter()
                    .closeProfileProxy(BluetoothProfile.MAP_CLIENT, mapProfile);
        }

        @Override
        public void onServiceDisconnected(int profile) {
            if (mMessage != null) {
                Log.d(LOG_TAG, "Bluetooth disconnected before sending the message");
                sendErrorInPendingIntent(mSentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
                mMessage = null;
            }
        }
    }
}
+13 −98
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
@@ -37,7 +36,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.UserManager;
import android.provider.Telephony;
import android.service.carrier.CarrierMessagingService;
import android.telephony.Rlog;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
@@ -96,6 +94,7 @@ public class IccSmsInterfaceManager {
    final protected AppOpsManager mAppOps;
    @VisibleForTesting
    public SmsDispatchersController mDispatchersController;
    private SmsPermissions mSmsPermissions;

    private final LocalLog mCellBroadcastLocalLog = new LocalLog(100);

@@ -157,6 +156,7 @@ public class IccSmsInterfaceManager {
        mContext = context;
        mAppOps = appOps;
        mDispatchersController = dispatchersController;
        mSmsPermissions = new SmsPermissions(phone, context, appOps);
    }

    protected void markMessagesAsRead(ArrayList<byte[]> messages) {
@@ -344,7 +344,7 @@ public class IccSmsInterfaceManager {
     */
    public void sendDataWithSelfPermissions(String callingPackage, String destAddr, String scAddr,
            int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
        if (!checkCallingOrSelfSendSmsPermission(callingPackage, "Sending SMS message")) {
        if (!mSmsPermissions.checkCallingOrSelfCanSendSms(callingPackage, "Sending SMS message")) {
            returnUnspecifiedFailure(sentIntent);
            return;
        }
@@ -359,7 +359,7 @@ public class IccSmsInterfaceManager {
    @UnsupportedAppUsage
    public void sendData(String callingPackage, String destAddr, String scAddr, int destPort,
            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
        if (!checkCallingSendSmsPermission(callingPackage, "Sending SMS message")) {
        if (!mSmsPermissions.checkCallingCanSendSms(callingPackage, "Sending SMS message")) {
            returnUnspecifiedFailure(sentIntent);
            return;
        }
@@ -409,15 +409,11 @@ public class IccSmsInterfaceManager {
    /**
     * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}.
     * This method checks only if the calling package has the permission to send the sms.
     * Note: SEND_SMS permission should be checked by the caller of this method
     */
    public void sendText(String callingPackage, String destAddr, String scAddr,
            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
            boolean persistMessageForNonDefaultSmsApp) {
        if (!checkCallingSendTextPermissions(
                persistMessageForNonDefaultSmsApp, callingPackage, "Sending SMS message")) {
            returnUnspecifiedFailure(sentIntent);
            return;
        }
        sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
                persistMessageForNonDefaultSmsApp, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
                false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
@@ -430,7 +426,7 @@ public class IccSmsInterfaceManager {
    public void sendTextWithSelfPermissions(String callingPackage, String destAddr, String scAddr,
            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
            boolean persistMessage) {
        if (!checkCallingOrSelfSendSmsPermission(callingPackage, "Sending SMS message")) {
        if (!mSmsPermissions.checkCallingOrSelfCanSendSms(callingPackage, "Sending SMS message")) {
            returnUnspecifiedFailure(sentIntent);
            return;
        }
@@ -552,7 +548,7 @@ public class IccSmsInterfaceManager {
            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
            boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore,
            int validityPeriod) {
        if (!checkCallingOrSelfSendSmsPermission(callingPackage, "Sending SMS message")) {
        if (!mSmsPermissions.checkCallingOrSelfCanSendSms(callingPackage, "Sending SMS message")) {
            returnUnspecifiedFailure(sentIntent);
            return;
        }
@@ -574,7 +570,7 @@ public class IccSmsInterfaceManager {
    public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                != PackageManager.PERMISSION_GRANTED) {
            enforceCallerIsImsAppOrCarrierApp("injectSmsPdu");
            mSmsPermissions.enforceCallerIsImsAppOrCarrierApp("injectSmsPdu");
        }

        if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
@@ -681,7 +677,7 @@ public class IccSmsInterfaceManager {
            String scAddr, List<String> parts, List<PendingIntent> sentIntents,
            List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp,
            int priority, boolean expectMore, int validityPeriod) {
        if (!checkCallingSendTextPermissions(
        if (!mSmsPermissions.checkCallingCanSendText(
                persistMessageForNonDefaultSmsApp, callingPackage, "Sending SMS message")) {
            returnUnspecifiedFailure(sentIntents);
            return;
@@ -1134,7 +1130,7 @@ public class IccSmsInterfaceManager {
    @UnsupportedAppUsage
    public void sendStoredText(String callingPkg, Uri messageUri, String scAddress,
            PendingIntent sentIntent, PendingIntent deliveryIntent) {
        if (!checkCallingSendSmsPermission(callingPkg, "Sending SMS message")) {
        if (!mSmsPermissions.checkCallingCanSendSms(callingPkg, "Sending SMS message")) {
            returnUnspecifiedFailure(sentIntent);
            return;
        }
@@ -1164,7 +1160,7 @@ public class IccSmsInterfaceManager {
    @UnsupportedAppUsage
    public void sendStoredMultipartText(String callingPkg, Uri messageUri, String scAddress,
            List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
        if (!checkCallingSendSmsPermission(callingPkg, "Sending SMS message")) {
        if (!mSmsPermissions.checkCallingCanSendSms(callingPkg, "Sending SMS message")) {
            returnUnspecifiedFailure(sentIntents);
            return;
        }
@@ -1318,87 +1314,6 @@ public class IccSmsInterfaceManager {
        }
    }

    /**
     * Check that the caller can send text messages.
     *
     * For persisted messages, the caller just needs the SEND_SMS permission. For unpersisted
     * messages, the caller must either be the IMS app or a carrier-privileged app, or they must
     * have both the MODIFY_PHONE_STATE and SEND_SMS permissions.
     *
     * @throws SecurityException if the caller is missing all necessary permission declaration or
     *                           has had a necessary runtime permission revoked.
     * @return true unless the caller has all necessary permissions but has a revoked AppOps bit.
     */
    @VisibleForTesting
    public boolean checkCallingSendTextPermissions(
            boolean persistMessageForNonDefaultSmsApp, String callingPackage, String message) {
        // TODO(b/75978989): Should we allow IMS/carrier apps for persisted messages as well?
        if (!persistMessageForNonDefaultSmsApp) {
            try {
                enforceCallerIsImsAppOrCarrierApp(message);
                // No need to also check SEND_SMS.
                return true;
            } catch (SecurityException e) {
                mContext.enforceCallingPermission(
                        android.Manifest.permission.MODIFY_PHONE_STATE, message);
            }
        }
        return checkCallingSendSmsPermission(callingPackage, message);
    }

    /**
     * Check that the caller (or self, if this is not an IPC) has SEND_SMS permissions.
     *
     * @throws SecurityException if the caller is missing the permission declaration or has had the
     *                           permission revoked at runtime.
     * @return whether the caller has the OP_SEND_SMS AppOps bit.
     */
    private boolean checkCallingOrSelfSendSmsPermission(String callingPackage, String message) {
        mContext.enforceCallingOrSelfPermission(Manifest.permission.SEND_SMS, message);
        return mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage)
                == AppOpsManager.MODE_ALLOWED;
    }

    /**
     * Check that the caller has SEND_SMS permissions. Can only be called during an IPC.
     *
     * @throws SecurityException if the caller is missing the permission declaration or has had the
     *                           permission revoked at runtime.
     * @return whether the caller has the OP_SEND_SMS AppOps bit.
     */
    private boolean checkCallingSendSmsPermission(String callingPackage, String message) {
        mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, message);
        return mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage)
                == AppOpsManager.MODE_ALLOWED;
    }

    /**
     * Enforces that the caller is one of the following apps:
     * <ul>
     *     <li> IMS App
     *     <li> Carrier App
     * </ul>
     */
    @VisibleForTesting
    public void enforceCallerIsImsAppOrCarrierApp(String message) {
        int callingUid = Binder.getCallingUid();
        String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
                new Intent(CarrierMessagingService.SERVICE_INTERFACE));
        try {
            if (carrierImsPackage != null
                    && callingUid == mContext.getPackageManager().getPackageUid(
                            carrierImsPackage, 0)) {
              return;
            }
        } catch (PackageManager.NameNotFoundException e) {
            if (Rlog.isLoggable("SMS", Log.DEBUG)) {
                log("Cannot find configured carrier ims package");
            }
        }

        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mPhone.getSubId(), message);
    }

    @UnsupportedAppUsage
    private String filterDestAddress(String destAddr) {
        String result  = null;
+3 −3
Original line number Diff line number Diff line
@@ -78,8 +78,8 @@ public class ProxyController {
    //PhoneSubInfoController to use proper PhoneSubInfoProxy object
    private PhoneSubInfoController mPhoneSubInfoController;

    //UiccSmsController to use proper IccSmsInterfaceManager object
    private UiccSmsController mUiccSmsController;
    //SmsController to use proper IccSmsInterfaceManager object
    private SmsController mSmsController;

    WakeLock mWakeLock;

@@ -136,7 +136,7 @@ public class ProxyController {

        mUiccPhoneBookController = new UiccPhoneBookController(mPhones);
        mPhoneSubInfoController = new PhoneSubInfoController(mContext, mPhones);
        mUiccSmsController = new UiccSmsController(mContext);
        mSmsController = new SmsController(mContext);
        mSetRadioAccessFamilyStatus = new int[mPhones.length];
        mNewRadioAccessFamily = new int[mPhones.length];
        mOldRadioAccessFamily = new int[mPhones.length];
+94 −59

File changed and moved.

Preview size limit exceeded, changes collapsed.

+135 −0
Original line number Diff line number Diff line
/*
 * 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.UnsupportedAppUsage;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.service.carrier.CarrierMessagingService;
import android.telephony.Rlog;
import android.util.Log;

/**
 * Permissions checks for SMS functionality
 */
public class SmsPermissions {
    static final String LOG_TAG = "SmsPermissions";

    @UnsupportedAppUsage
    private final Phone mPhone;
    @UnsupportedAppUsage
    private final Context mContext;
    @UnsupportedAppUsage
    private final AppOpsManager mAppOps;

    public SmsPermissions(Phone phone, Context context, AppOpsManager appOps) {
        mPhone = phone;
        mContext = context;
        mAppOps = appOps;
    }

    /**
     * Check that the caller can send text messages.
     *
     * For persisted messages, the caller just needs the SEND_SMS permission. For unpersisted
     * For persisted messages, the caller just needs the SEND_SMS permission. For unpersisted
     * messages, the caller must either be the IMS app or a carrier-privileged app, or they must
     * have both the MODIFY_PHONE_STATE and SEND_SMS permissions.
     *
     * @throws SecurityException if the caller is missing all necessary permission declaration or
     *                           has had a necessary runtime permission revoked.
     * @return true unless the caller has all necessary permissions but has a revoked AppOps bit.
     */
    public boolean checkCallingCanSendText(
            boolean persistMessageForNonDefaultSmsApp, String callingPackage, String message) {
        // TODO(b/75978989): Should we allow IMS/carrier apps for persisted messages as well?
        if (!persistMessageForNonDefaultSmsApp) {
            try {
                enforceCallerIsImsAppOrCarrierApp(message);
                // No need to also check SEND_SMS.
                return true;
            } catch (SecurityException e) {
                mContext.enforceCallingPermission(
                        android.Manifest.permission.MODIFY_PHONE_STATE, message);
            }
        }
        return checkCallingCanSendSms(callingPackage, message);
    }


    /**
     * Enforces that the caller is one of the following apps:
     * <ul>
     *     <li> IMS App
     *     <li> Carrier App
     * </ul>
     */
    public void enforceCallerIsImsAppOrCarrierApp(String message) {
        int callingUid = Binder.getCallingUid();
        String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
                new Intent(CarrierMessagingService.SERVICE_INTERFACE));
        try {
            if (carrierImsPackage != null
                    && callingUid == mContext.getPackageManager().getPackageUid(
                    carrierImsPackage, 0)) {
                return;
            }
        } catch (PackageManager.NameNotFoundException e) {
            if (Rlog.isLoggable("SMS", Log.DEBUG)) {
                log("Cannot find configured carrier ims package");
            }
        }

        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mPhone.getSubId(), message);
    }


    /**
     * Check that the caller has SEND_SMS permissions. Can only be called during an IPC.
     *
     * @throws SecurityException if the caller is missing the permission declaration or has had the
     *                           permission revoked at runtime.
     * @return whether the caller has the OP_SEND_SMS AppOps bit.
     */
    public boolean checkCallingCanSendSms(String callingPackage, String message) {
        mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, message);
        return mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage)
                == AppOpsManager.MODE_ALLOWED;
    }

    /**
     * Check that the caller (or self, if this is not an IPC) has SEND_SMS permissions.
     *
     * @throws SecurityException if the caller is missing the permission declaration or has had the
     *                           permission revoked at runtime.
     * @return whether the caller has the OP_SEND_SMS AppOps bit.
     */
    public boolean checkCallingOrSelfCanSendSms(String callingPackage, String message) {
        mContext.enforceCallingOrSelfPermission(Manifest.permission.SEND_SMS, message);
        return mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage)
                == AppOpsManager.MODE_ALLOWED;
    }

    @UnsupportedAppUsage
    protected void log(String msg) {
        Log.d(LOG_TAG, "[IccSmsInterfaceManager] " + msg);
    }
}
Loading