content: /*
   * 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);
      }
  }
  