/** FIXME replace this with some other way of making these instances */
  public static void makeDefaultPhone(Context context) {
    synchronized (sLockProxyPhones) {
      if (!sMadeDefaults) {
        sContext = context;

        // create the telephony device controller.
        TelephonyDevController.create();

        int retryCount = 0;
        for (; ; ) {
          boolean hasException = false;
          retryCount++;

          try {
            // use UNIX domain socket to
            // prevent subsequent initialization
            new LocalServerSocket("com.android.internal.telephony");
          } catch (java.io.IOException ex) {
            hasException = true;
          }

          if (!hasException) {
            break;
          } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
            throw new RuntimeException("PhoneFactory probably already running");
          } else {
            try {
              Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
            } catch (InterruptedException er) {
            }
          }
        }

        sPhoneNotifier = new DefaultPhoneNotifier();

        int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);
        Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);

        /* In case of multi SIM mode two instances of PhoneProxy, RIL are created,
        where as in single SIM mode only instance. isMultiSimEnabled() function checks
        whether it is single SIM or multi SIM mode */
        int numPhones = TelephonyManager.getDefault().getPhoneCount();
        int[] networkModes = new int[numPhones];
        sProxyPhones = new PhoneProxy[numPhones];
        sCommandsInterfaces = new RIL[numPhones];

        for (int i = 0; i < numPhones; i++) {
          // reads the system properties and makes commandsinterface
          // Get preferred network type.
          networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;

          Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
          sCommandsInterfaces[i] = new RIL(context, networkModes[i], cdmaSubscription, i);
        }
        Rlog.i(LOG_TAG, "Creating SubscriptionController");
        SubscriptionController.init(context, sCommandsInterfaces);

        // Instantiate UiccController so that all other classes can just
        // call getInstance()
        mUiccController = UiccController.make(context, sCommandsInterfaces);

        for (int i = 0; i < numPhones; i++) {
          PhoneBase phone = null;
          int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
          if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
            phone = new GSMPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i);
          } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
            phone = new CDMALTEPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i);
          }
          Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);

          sProxyPhones[i] = new PhoneProxy(phone);
        }
        mProxyController =
            ProxyController.getInstance(
                context, sProxyPhones, mUiccController, sCommandsInterfaces);

        // Set the default phone in base class.
        // FIXME: This is a first best guess at what the defaults will be. It
        // FIXME: needs to be done in a more controlled manner in the future.
        sProxyPhone = sProxyPhones[0];
        sCommandsInterface = sCommandsInterfaces[0];

        // Ensure that we have a default SMS app. Requesting the app with
        // updateIfNeeded set to true is enough to configure a default SMS app.
        ComponentName componentName =
            SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */);
        String packageName = "NONE";
        if (componentName != null) {
          packageName = componentName.getPackageName();
        }
        Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName);

        // Set up monitor to watch for changes to SMS packages
        SmsApplication.initSmsPackageMonitor(context);

        sMadeDefaults = true;

        Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
        sSubInfoRecordUpdater =
            new SubscriptionInfoUpdater(context, sProxyPhones, sCommandsInterfaces);
        SubscriptionController.getInstance().updatePhonesAvailability(sProxyPhones);

        // Start monitoring after defaults have been made.
        // Default phone must be ready before ImsPhone is created
        // because ImsService might need it when it is being opened.
        for (int i = 0; i < numPhones; i++) {
          sProxyPhones[i].startMonitoringImsService();
        }
      }
    }
  }
Example #2
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;
    }
  }