Beispiel #1
0
  /**
   * Dispatches inbound messages that are in the WAP PDU format. See wap-230-wsp-20010705-a section
   * 8 for details on the WAP PDU format.
   *
   * @param pdu The WAP PDU, made up of one or more SMS PDUs
   * @return a result code from {@link android.provider.Telephony.Sms.Intents}, or {@link
   *     Activity#RESULT_OK} if the message has been broadcast to applications
   */
  public int dispatchWapPdu(byte[] pdu, BroadcastReceiver receiver, InboundSmsHandler handler) {

    if (DBG) Rlog.d(TAG, "Rx: " + IccUtils.bytesToHexString(pdu));

    try {
      int index = 0;
      int transactionId = pdu[index++] & 0xFF;
      int pduType = pdu[index++] & 0xFF;

      // Should we "abort" if no subId for now just no supplying extra param below
      int phoneId = handler.getPhone().getPhoneId();

      if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH)
          && (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
        index =
            mContext
                .getResources()
                .getInteger(com.android.internal.R.integer.config_valid_wappush_index);
        if (index != -1) {
          transactionId = pdu[index++] & 0xff;
          pduType = pdu[index++] & 0xff;
          if (DBG)
            Rlog.d(
                TAG,
                "index = "
                    + index
                    + " PDU Type = "
                    + pduType
                    + " transactionID = "
                    + transactionId);

          // recheck wap push pduType
          if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH)
              && (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
            if (DBG) Rlog.w(TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
            return Intents.RESULT_SMS_HANDLED;
          }
        } else {
          if (DBG) Rlog.w(TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
          return Intents.RESULT_SMS_HANDLED;
        }
      }

      WspTypeDecoder pduDecoder = new WspTypeDecoder(pdu);

      /**
       * Parse HeaderLen(unsigned integer). From wap-230-wsp-20010705-a section 8.1.2 The maximum
       * size of a uintvar is 32 bits. So it will be encoded in no more than 5 octets.
       */
      if (pduDecoder.decodeUintvarInteger(index) == false) {
        if (DBG) Rlog.w(TAG, "Received PDU. Header Length error.");
        return Intents.RESULT_SMS_GENERIC_ERROR;
      }
      int headerLength = (int) pduDecoder.getValue32();
      index += pduDecoder.getDecodedDataLength();

      int headerStartIndex = index;

      /**
       * Parse Content-Type. From wap-230-wsp-20010705-a section 8.4.2.24
       *
       * <p>Content-type-value = Constrained-media | Content-general-form Content-general-form =
       * Value-length Media-type Media-type = (Well-known-media | Extension-Media) *(Parameter)
       * Value-length = Short-length | (Length-quote Length) Short-length = <Any octet 0-30> (octet
       * <= WAP_PDU_SHORT_LENGTH_MAX) Length-quote = <Octet 31> (WAP_PDU_LENGTH_QUOTE) Length =
       * Uintvar-integer
       */
      if (pduDecoder.decodeContentType(index) == false) {
        if (DBG) Rlog.w(TAG, "Received PDU. Header Content-Type error.");
        return Intents.RESULT_SMS_GENERIC_ERROR;
      }

      String mimeType = pduDecoder.getValueString();
      long binaryContentType = pduDecoder.getValue32();
      index += pduDecoder.getDecodedDataLength();

      byte[] header = new byte[headerLength];
      System.arraycopy(pdu, headerStartIndex, header, 0, header.length);

      byte[] intentData;

      if (mimeType != null && mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) {
        intentData = pdu;
      } else {
        int dataIndex = headerStartIndex + headerLength;
        intentData = new byte[pdu.length - dataIndex];
        System.arraycopy(pdu, dataIndex, intentData, 0, intentData.length);
      }

      if (SmsManager.getDefault().getAutoPersisting()) {
        // Store the wap push data in telephony
        long[] subIds = SubscriptionManager.getSubId(phoneId);
        // FIXME (tomtaylor) - when we've updated SubscriptionManager, change
        // SubscriptionManager.DEFAULT_SUB_ID to SubscriptionManager.getDefaultSmsSubId()
        long subId =
            (subIds != null) && (subIds.length > 0) ? subIds[0] : SmsManager.getDefaultSmsSubId();
        writeInboxMessage(subId, intentData);
      }

      /**
       * Seek for application ID field in WSP header. If application ID is found, WapPushManager
       * substitute the message processing. Since WapPushManager is optional module, if
       * WapPushManager is not found, legacy message processing will be continued.
       */
      if (pduDecoder.seekXWapApplicationId(index, index + headerLength - 1)) {
        index = (int) pduDecoder.getValue32();
        pduDecoder.decodeXWapApplicationId(index);
        String wapAppId = pduDecoder.getValueString();
        if (wapAppId == null) {
          wapAppId = Integer.toString((int) pduDecoder.getValue32());
        }

        String contentType = ((mimeType == null) ? Long.toString(binaryContentType) : mimeType);
        if (DBG) Rlog.v(TAG, "appid found: " + wapAppId + ":" + contentType);

        try {
          boolean processFurther = true;
          IWapPushManager wapPushMan = mWapPushManager;

          if (wapPushMan == null) {
            if (DBG) Rlog.w(TAG, "wap push manager not found!");
          } else {
            Intent intent = new Intent();
            intent.putExtra("transactionId", transactionId);
            intent.putExtra("pduType", pduType);
            intent.putExtra("header", header);
            intent.putExtra("data", intentData);
            intent.putExtra("contentTypeParameters", pduDecoder.getContentParameters());
            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);

            int procRet = wapPushMan.processMessage(wapAppId, contentType, intent);
            if (DBG) Rlog.v(TAG, "procRet:" + procRet);
            if ((procRet & WapPushManagerParams.MESSAGE_HANDLED) > 0
                && (procRet & WapPushManagerParams.FURTHER_PROCESSING) == 0) {
              processFurther = false;
            }
          }
          if (!processFurther) {
            return Intents.RESULT_SMS_HANDLED;
          }
        } catch (RemoteException e) {
          if (DBG) Rlog.w(TAG, "remote func failed...");
        }
      }
      if (DBG) Rlog.v(TAG, "fall back to existing handler");

      if (mimeType == null) {
        if (DBG) Rlog.w(TAG, "Header Content-Type error.");
        return Intents.RESULT_SMS_GENERIC_ERROR;
      }

      String permission;
      int appOp;

      if (mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_MMS)) {
        permission = android.Manifest.permission.RECEIVE_MMS;
        appOp = AppOpsManager.OP_RECEIVE_MMS;
      } else {
        permission = android.Manifest.permission.RECEIVE_WAP_PUSH;
        appOp = AppOpsManager.OP_RECEIVE_WAP_PUSH;
      }

      Intent intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION);
      intent.setType(mimeType);
      intent.putExtra("transactionId", transactionId);
      intent.putExtra("pduType", pduType);
      intent.putExtra("header", header);
      intent.putExtra("data", intentData);
      intent.putExtra("contentTypeParameters", pduDecoder.getContentParameters());
      SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);

      // Direct the intent to only the default MMS app. If we can't find a default MMS app
      // then sent it to all broadcast receivers.
      ComponentName componentName = SmsApplication.getDefaultMmsApplication(mContext, true);
      if (componentName != null) {
        // Deliver MMS message only to this receiver
        intent.setComponent(componentName);
        if (DBG)
          Rlog.v(
              TAG,
              "Delivering MMS to: "
                  + componentName.getPackageName()
                  + " "
                  + componentName.getClassName());
      }

      handler.dispatchIntent(intent, permission, appOp, receiver, UserHandle.OWNER);
      return Activity.RESULT_OK;
    } catch (ArrayIndexOutOfBoundsException aie) {
      // 0-byte WAP PDU or other unexpected WAP PDU contents can easily throw this;
      // log exception string without stack trace and return false.
      Rlog.e(TAG, "ignoring dispatchWapPdu() array index exception: " + aie);
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }
  }
  /**
   * Dispatches inbound messages that are in the WAP PDU format. See wap-230-wsp-20010705-a section
   * 8 for details on the WAP PDU format.
   *
   * @param pdu The WAP PDU, made up of one or more SMS PDUs
   * @return a result code from {@link Telephony.Sms.Intents}, or {@link Activity#RESULT_OK} if the
   *     message has been broadcast to applications
   */
  public int dispatchWapPdu(byte[] pdu) {

    if (false) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));

    int index = 0;
    int transactionId = pdu[index++] & 0xFF;
    int pduType = pdu[index++] & 0xFF;
    int headerLength = 0;

    if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH)
        && (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
      if (false) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
      return Intents.RESULT_SMS_HANDLED;
    }

    pduDecoder = new WspTypeDecoder(pdu);

    /**
     * Parse HeaderLen(unsigned integer). From wap-230-wsp-20010705-a section 8.1.2 The maximum size
     * of a uintvar is 32 bits. So it will be encoded in no more than 5 octets.
     */
    if (pduDecoder.decodeUintvarInteger(index) == false) {
      if (false) Log.w(LOG_TAG, "Received PDU. Header Length error.");
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }
    headerLength = (int) pduDecoder.getValue32();
    index += pduDecoder.getDecodedDataLength();

    int headerStartIndex = index;

    /**
     * Parse Content-Type. From wap-230-wsp-20010705-a section 8.4.2.24
     *
     * <p>Content-type-value = Constrained-media | Content-general-form Content-general-form =
     * Value-length Media-type Media-type = (Well-known-media | Extension-Media) *(Parameter)
     * Value-length = Short-length | (Length-quote Length) Short-length = <Any octet 0-30> (octet <=
     * WAP_PDU_SHORT_LENGTH_MAX) Length-quote = <Octet 31> (WAP_PDU_LENGTH_QUOTE) Length =
     * Uintvar-integer
     */
    if (pduDecoder.decodeContentType(index) == false) {
      if (false) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }

    String mimeType = pduDecoder.getValueString();
    long binaryContentType = pduDecoder.getValue32();
    index += pduDecoder.getDecodedDataLength();

    byte[] header = new byte[headerLength];
    System.arraycopy(pdu, headerStartIndex, header, 0, header.length);

    byte[] intentData;

    if (mimeType != null && mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) {
      intentData = pdu;
    } else {
      int dataIndex = headerStartIndex + headerLength;
      intentData = new byte[pdu.length - dataIndex];
      System.arraycopy(pdu, dataIndex, intentData, 0, intentData.length);
    }

    /**
     * Seek for application ID field in WSP header. If application ID is found, WapPushManager
     * substitute the message processing. Since WapPushManager is optional module, if WapPushManager
     * is not found, legacy message processing will be continued.
     */
    if (pduDecoder.seekXWapApplicationId(index, index + headerLength - 1)) {
      index = (int) pduDecoder.getValue32();
      pduDecoder.decodeXWapApplicationId(index);
      String wapAppId = pduDecoder.getValueString();
      if (wapAppId == null) {
        wapAppId = Integer.toString((int) pduDecoder.getValue32());
      }

      String contentType = ((mimeType == null) ? Long.toString(binaryContentType) : mimeType);
      if (false) Log.v(LOG_TAG, "appid found: " + wapAppId + ":" + contentType);

      try {
        boolean processFurther = true;
        IWapPushManager wapPushMan = mWapConn.getWapPushManager();

        if (wapPushMan == null) {
          if (false) Log.w(LOG_TAG, "wap push manager not found!");
        } else {
          Intent intent = new Intent();
          intent.putExtra("transactionId", transactionId);
          intent.putExtra("pduType", pduType);
          intent.putExtra("header", header);
          intent.putExtra("data", intentData);
          intent.putExtra("contentTypeParameters", pduDecoder.getContentParameters());

          int procRet = wapPushMan.processMessage(wapAppId, contentType, intent);
          if (false) Log.v(LOG_TAG, "procRet:" + procRet);
          if ((procRet & WapPushManagerParams.MESSAGE_HANDLED) > 0
              && (procRet & WapPushManagerParams.FURTHER_PROCESSING) == 0) {
            processFurther = false;
          }
        }
        if (!processFurther) {
          return Intents.RESULT_SMS_HANDLED;
        }
      } catch (RemoteException e) {
        if (false) Log.w(LOG_TAG, "remote func failed...");
      }
    }
    if (false) Log.v(LOG_TAG, "fall back to existing handler");

    if (mimeType == null) {
      if (false) Log.w(LOG_TAG, "Header Content-Type error.");
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }

    String permission;

    if (mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_MMS)) {
      permission = "android.permission.RECEIVE_MMS";
    } else {
      permission = "android.permission.RECEIVE_WAP_PUSH";
    }

    Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
    intent.setType(mimeType);
    intent.putExtra("transactionId", transactionId);
    intent.putExtra("pduType", pduType);
    intent.putExtra("header", header);
    intent.putExtra("data", intentData);
    intent.putExtra("contentTypeParameters", pduDecoder.getContentParameters());

    mSmsDispatcher.dispatch(intent, permission);

    return Activity.RESULT_OK;
  }