小区广播接收流程

1.0、我们从frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java makeGsmCellBroadcastHandler开始

/**
     * Create a new CellBroadcastHandler.
     * @param context the context to use for dispatching Intents
     * @return the new handler
     */
    public static GsmCellBroadcastHandler makeGsmCellBroadcastHandler(Context context,
            PhoneBase phone) {
        GsmCellBroadcastHandler handler = new GsmCellBroadcastHandler(context, phone);
        handler.start();
        return handler;
    }

1.1 通过调用GsmCellBroadcastHandler对象 handler.start()调用handleSmsMessage

 /**
     * Handle 3GPP-format Cell Broadcast messages sent from radio.
     *
     * @param message the message to process
     * @return true if an ordered broadcast was sent; false on failure
     */
    @Override
    protected boolean handleSmsMessage(Message message) {
        if (message.obj instanceof AsyncResult) {
            SmsCbMessage cbMessage = handleGsmBroadcastSms((AsyncResult) message.obj);
            if (cbMessage != null) {
                handleBroadcastSms(cbMessage);
                return true;
            }
        }
        return super.handleSmsMessage(message);
    }

1.2 handleGsmBroadcastSms中MTK在实例化SmsCbHeader对象的时候,将所有的小区广播都初始化为非ETWS primary message。

/**
    * Handle 3GPP format SMS-CB message.
    * @param ar the AsyncResult containing the received PDUs
    */
   private SmsCbMessage handleGsmBroadcastSms(AsyncResult ar) {
       try {
                 ..................
            // MTK-START, set it is not a ETWS primary message
           SmsCbHeader header = new SmsCbHeader(receivedPdu, false);
           // MTK-END
          ..................
           return GsmSmsCbMessage.createSmsCbMessage(header, location, pdus);} catch (RuntimeException e) {
           loge("Error in decoding SMS CB pdu", e);
           return null;
       }
   }

1.3 我们来看看createSmsCbMessage,从上面实例化的对象来看,代码会走到else里面。priority这属性很重要,它用来区别是一般的小区广播还是紧急的小区广播

/**
   * Create a new SmsCbMessage object from a header object plus one or more received PDUs.
   *
   * @param pdus PDU bytes
   */
  static SmsCbMessage createSmsCbMessage(SmsCbHeader header, SmsCbLocation location,
          byte[][] pdus) throws IllegalArgumentException {
      if (header.isEtwsPrimaryNotification()) {
          return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
                  header.getGeographicalScope(), header.getSerialNumber(),
                  location, header.getServiceCategory(),
                  null, "ETWS", SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
                  header.getEtwsInfo(), header.getCmasInfo());
      } else {
          String language = null;
          StringBuilder sb = new StringBuilder();
          for (byte[] pdu : pdus) {
              Pair<String, String> p = parseBody(header, pdu);
              language = p.first;
              sb.append(p.second);
          }
          int priority = header.isEmergencyMessage() ? SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY
                  : SmsCbMessage.MESSAGE_PRIORITY_NORMAL;return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
                  header.getGeographicalScope(), header.getSerialNumber(), location,
                  header.getServiceCategory(), language, sb.toString(), priority,
                  header.getEtwsInfo(), header.getCmasInfo());
      }
  }

1.4 从isEmergencyMessage()可以看出当mMessageIdentifier 在SmsCbConstants.MESSAGE_ID_PWS_FIRST_IDENTIFIER、mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_PWS_LAST_IDENTIFIER之间就是紧急小区广播。mMessageIdentifier它就是上面 1.2 中实例化SmsCbHeader对象时指定的。

/**
   * Return whether this broadcast is an emergency (PWS) message type.
   * @return true if this message is emergency type; false otherwise
   */
  boolean isEmergencyMessage() {
      return mMessageIdentifier >= SmsCbConstants.MESSAGE_ID_PWS_FIRST_IDENTIFIER
              && mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_PWS_LAST_IDENTIFIER;
  }

1.5 经过以上步骤,小区广播的实例化完毕,然后会调用1.1 中的handleBroadcastSms来广播。

/**
   * Dispatch a Cell Broadcast message to listeners.
   * @param message the Cell Broadcast to broadcast
   */
  protected void handleBroadcastSms(SmsCbMessage message, boolean isPrimary) {
      String receiverPermission;
      int appOp;
​
      Intent intent;
      if (message.isEmergencyMessage()) {
          log("Dispatching emergency SMS CB, SmsCbMessage is: " + message);
          intent = new Intent(Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION);
          // MTK-START
          intent.putExtra(SmsConstants.IS_EMERGENCY_CB_PRIMARY, isPrimary);
          // MTK-END
          receiverPermission = Manifest.permission.RECEIVE_EMERGENCY_BROADCAST;
          appOp = AppOpsManager.OP_RECEIVE_EMERGECY_SMS;
      } else {
          log("Dispatching SMS CB, SmsCbMessage is: " + message);
          intent = new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION);
          receiverPermission = Manifest.permission.RECEIVE_SMS;
          appOp = AppOpsManager.OP_RECEIVE_SMS;
      }
      intent.putExtra("message", message);
      SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
      mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, receiverPermission, appOp,
              mReceiver, getHandler(), Activity.RESULT_OK, null, null);
  }

从上面的代码可以看出,如果是紧急小区广播intent就会标示为SMS_EMERGENCY_CB_RECEIVED_ACTION,普通的就为SMS_CB_RECEIVED_ACTION
下面我们来看看上层接收到广播以后出来流程
packages/apps/CellBroadcastReceiver/src/com/android/cellbroadcastreceiver/CellBroadcastReceiver.java
vendor/mediatek/proprietary/packages/apps/CMASReceiver/src/com/mediatek/cellbroadcastreceiver/CellBroadcastReceiver.java

protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
       ............
    } else if (Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION.equals(action)) {
           .......
            if (privileged) {
                intent.setClass(context, CellBroadcastAlertService.class);
                context.startService(intent);
            } else {
                loge("ignoring unprivileged action received " + action);
            }
        } 
...........}

1、当接收到紧急小区广播会启动CellBroadcastAlertService服务。

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String action = intent.getAction();
        if (Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION.equals(action) ||
                Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION.equals(action)) {
            handleCellBroadcastIntent(intent);
        } else if (SHOW_NEW_ALERT_ACTION.equals(action)) {
            try {
                if (UserHandle.myUserId() ==
                        ActivityManagerNative.getDefault().getCurrentUser().id) {
                    showNewAlert(intent);
                } else {
                    Log.d(TAG,"Not active user, ignore the alert display");
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        } else {
            Log.e(TAG, "Unrecognized intent action: " + action);
        }
        return START_NOT_STICKY;
    }

1.6 当服务开启以后,handleCellBroadcastIntent会重新新建一个广播showNewAlert。

private void showNewAlert(Intent intent) {
        Bundle extras = intent.getExtras();
        if (extras == null) {
            Log.e(TAG, "received SHOW_NEW_ALERT_ACTION with no extras!");
            return;
        }
​
        CellBroadcastMessage cbm = (CellBroadcastMessage) intent.getParcelableExtra("message");if (cbm == null) {
            Log.e(TAG, "received SHOW_NEW_ALERT_ACTION with no message extra");
            return;
        }if (CellBroadcastConfigService.isEmergencyAlertMessage(cbm)) {
            // start alert sound / vibration / TTS and display full-screen alert
            openEmergencyAlertNotification(cbm);
        } else {
            // add notification to the bar
            addToNotificationBar(cbm);
        }
    }

当判断小区广播为紧急小区广播会调用openEmergencyAlertNotification(cbm)。

 /**
     * Display a full-screen alert message for emergency alerts.
     * @param message the alert to display
     */
    private void openEmergencyAlertNotification(CellBroadcastMessage message) {
      
..............
        // start audio/vibration/speech service for emergency alerts
        Intent audioIntent = new Intent(this, CellBroadcastAlertAudio.class);
        audioIntent.setAction(CellBroadcastAlertAudio.ACTION_START_ALERT_AUDIO);.............
        startService(audioIntent);
    }

1.7 然后启动CellBroadcastAlertAudio服务
packages/apps/CellBroadcastReceiver/src/com/android/cellbroadcastreceiver/CellBroadcastAlertAudio.java
vendor/mediatek/proprietary/packages/apps/CMASReceiver/src/com/mediatek/cellbroadcastreceiver/CellBroadcastAlertAudio.java

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // No intent, tell the system not to restart us.
        if (intent == null) {
            stopSelf();
            return START_NOT_STICKY;
        }// This extra should always be provided by CellBroadcastAlertService,
        // but default to 10.5 seconds just to be safe (CMAS requirement).
        int duration = intent.getIntExtra(ALERT_AUDIO_DURATION_EXTRA, 10500);
        if (SystemProperties.get("ro.mtk_gemini_support").equals("1")) {
            mSubId = intent.getIntExtra("subscription", -1);
        }
        mHasTempVolume = intent.getBooleanExtra("has_alert_volume", false);
        if (mHasTempVolume) {
            mTempVolume = intent.getFloatExtra("alert_volume", 1.0f);
        }// Get text to speak (if enabled by user)
        mMessageBody = intent.getStringExtra(ALERT_AUDIO_MESSAGE_BODY);
        mMessageLanguage = intent.getStringExtra(ALERT_AUDIO_MESSAGE_LANGUAGE);
​
        mEnableVibrate = intent.getBooleanExtra(ALERT_AUDIO_VIBRATE_EXTRA, true);
        /*if (intent.getBooleanExtra(ALERT_AUDIO_ETWS_VIBRATE_EXTRA, false)) {
            mEnableVibrate = true;  // force enable vibration for ETWS alerts
        }*/switch (mAudioManager.getRingerMode()) {
            case AudioManager.RINGER_MODE_SILENT:
                if (DBG) log("Ringer mode: silent");
                mEnableAudio = false;
                mEnableVibrate = false;
                break;case AudioManager.RINGER_MODE_VIBRATE:
                if (DBG) log("Ringer mode: vibrate");
                mEnableAudio = false;
                break;case AudioManager.RINGER_MODE_NORMAL:
            default:
                if (DBG) log("Ringer mode: normal");
                mEnableAudio = true;
                break;
        }if (mMessageBody != null && mEnableAudio) {
            if (mTts == null) {
                mTts = new TextToSpeech(this, this);
            } else if (mTtsEngineReady) {
                setTtsLanguage();
            }
        }if (mEnableAudio || mEnableVibrate) {
            play(duration);     // in milliseconds
        } else {
            stopSelf();
            return START_NOT_STICKY;
        }// Record the initial call state here so that the new alarm has the
        // newest state.
        mInitialCallState = mTelephonyManager.getCallState();return START_STICKY;
    }

CellBroadcastAlertAudio启动以后会根据当前的情景模式 响铃或者震动。
1.6 步骤中如果判断为一般小区广播会调用addToNotificationBar,

/**
     * Add the new alert to the notification bar (non-emergency alerts), or launch a
     * high-priority immediate intent for emergency alerts.
     * @param message the alert to display
     */
    private void addToNotificationBar(CellBroadcastMessage message) {
        int channelTitleId = CellBroadcastResources.getDialogTitleResource(message);
        CharSequence channelName = getText(channelTitleId);
        String messageBody = message.getMessageBody();// Pass the list of unread non-emergency CellBroadcastMessages
        ArrayList<CellBroadcastMessage> messageList = CellBroadcastReceiverApp
                .addNewMessageToList(message);// Create intent to show the new messages when user selects the notification.
        Intent intent = createDisplayMessageIntent(this, CellBroadcastAlertDialog.class,
                messageList);
        intent.putExtra(CellBroadcastAlertFullScreen.FROM_NOTIFICATION_EXTRA, true);
​
        PendingIntent pi = PendingIntent.getActivity(this, NOTIFICATION_ID, intent,
                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);// use default sound/vibration/lights for non-emergency broadcasts
        Notification.Builder builder = new Notification.Builder(this)
                .setSmallIcon(R.drawable.ic_notify_alert)
                .setTicker(channelName)
                .setWhen(System.currentTimeMillis())
                .setContentIntent(pi)
                .setCategory(Notification.CATEGORY_SYSTEM)
                .setPriority(Notification.PRIORITY_HIGH)
                .setColor(getResources().getColor(R.color.notification_color))
                .setVisibility(Notification.VISIBILITY_PUBLIC)
                .setDefaults(Notification.DEFAULT_ALL);
​
        builder.setDefaults(Notification.DEFAULT_ALL);// increment unread alert count (decremented when user dismisses alert dialog)
        int unreadCount = messageList.size();
        if (unreadCount > 1) {
            // use generic count of unread broadcasts if more than one unread
            builder.setContentTitle(getString(R.string.notification_multiple_title));
            builder.setContentText(getString(R.string.notification_multiple, unreadCount));
        } else {
            builder.setContentTitle(channelName).setContentText(messageBody);
        }
        
        Notification note = builder.build();
        note.defaults |= Notification.DEFAULT_SOUND;
        
        note.defaults |= Notification.DEFAULT_VIBRATE; 
        long[] vibrate = {0,100,200,300}; 
        note.vibrate = vibrate;
​
        NotificationManager notificationManager =
            (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
​
        notificationManager.notify(NOTIFICATION_ID, note);
    }
    ```
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值