• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.satellite;
18 
19 import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS;
20 import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_SMS;
21 import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN;
22 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
23 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
24 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED;
25 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN;
26 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT;
27 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NETWORK_ERROR;
28 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE;
29 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
30 
31 import static com.android.internal.telephony.SmsDispatchersController.PendingRequest;
32 import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT;
33 
34 import android.annotation.NonNull;
35 import android.annotation.Nullable;
36 import android.content.Context;
37 import android.content.res.Resources;
38 import android.os.AsyncResult;
39 import android.os.Handler;
40 import android.os.Looper;
41 import android.os.Message;
42 import android.telephony.PersistentLogger;
43 import android.telephony.satellite.SatelliteDatagram;
44 import android.telephony.satellite.SatelliteManager;
45 import android.telephony.satellite.SatelliteSessionStats;
46 import android.util.Log;
47 
48 import com.android.internal.R;
49 import com.android.internal.annotations.GuardedBy;
50 import com.android.internal.annotations.VisibleForTesting;
51 import com.android.internal.os.SomeArgs;
52 import com.android.internal.telephony.Phone;
53 import com.android.internal.telephony.SmsDispatchersController;
54 import com.android.internal.telephony.flags.FeatureFlags;
55 import com.android.internal.telephony.metrics.SatelliteStats;
56 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
57 import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
58 
59 import java.util.LinkedHashMap;
60 import java.util.Map.Entry;
61 import java.util.Set;
62 import java.util.concurrent.TimeUnit;
63 import java.util.concurrent.atomic.AtomicBoolean;
64 import java.util.concurrent.atomic.AtomicLong;
65 import java.util.function.Consumer;
66 
67 /**
68  * Datagram dispatcher used to send satellite datagrams.
69  */
70 public class DatagramDispatcher extends Handler {
71     private static final String TAG = "DatagramDispatcher";
72 
73     private static final int CMD_SEND_SATELLITE_DATAGRAM = 1;
74     private static final int EVENT_SEND_SATELLITE_DATAGRAM_DONE = 2;
75     private static final int EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT = 3;
76     private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT = 4;
77     private static final int EVENT_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMED_OUT = 5;
78     private static final int EVENT_ABORT_SENDING_SATELLITE_DATAGRAMS_DONE = 6;
79     private static final int EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT = 7;
80     private static final int CMD_SEND_SMS = 8;
81     private static final int EVENT_SEND_SMS_DONE = 9;
82     private static final int EVENT_MT_SMS_POLLING_THROTTLE_TIMED_OUT = 10;
83     private static final int CMD_SEND_MT_SMS_POLLING_MESSAGE = 11;
84 
85     private static final Long TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE = TimeUnit.SECONDS.toMillis(10);
86     @NonNull private static DatagramDispatcher sInstance;
87     @NonNull private final Context mContext;
88     @NonNull private final DatagramController mDatagramController;
89     @NonNull private final ControllerMetricsStats mControllerMetricsStats;
90     @NonNull private final SessionMetricsStats mSessionMetricsStats;
91     @NonNull private final FeatureFlags mFeatureFlags;
92 
93     private boolean mIsDemoMode = false;
94     private boolean mIsAligned = false;
95     private DatagramDispatcherHandlerRequest mSendSatelliteDatagramRequest = null;
96 
97     private static AtomicLong mNextDatagramId = new AtomicLong(0);
98 
99     private AtomicBoolean mShouldSendDatagramToModemInDemoMode = null;
100 
101     private final Object mLock = new Object();
102     private long mDemoTimeoutDuration = TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE;
103 
104     /** {@code true} if already sent an emergency datagram during a session */
105     @GuardedBy("mLock")
106     private boolean mIsEmergencyCommunicationEstablished = false;
107 
108     @GuardedBy("mLock")
109     private boolean mSendingInProgress;
110 
111     /**
112      * Map key: datagramId, value: SendSatelliteDatagramArgument to retry sending emergency
113      * datagrams.
114      */
115     @GuardedBy("mLock")
116     private final LinkedHashMap<Long, SendSatelliteDatagramArgument>
117             mPendingEmergencyDatagramsMap = new LinkedHashMap<>();
118 
119     /**
120      * Map key: datagramId, value: SendSatelliteDatagramArgument to retry sending non-emergency
121      * datagrams.
122      */
123     @GuardedBy("mLock")
124     private final LinkedHashMap<Long, SendSatelliteDatagramArgument>
125             mPendingNonEmergencyDatagramsMap = new LinkedHashMap<>();
126 
127     /**
128      * Map key: messageId, value: {@link PendingRequest} which contains all the information to send
129      * carrier roaming nb iot ntn SMS.
130      */
131     @GuardedBy("mLock")
132     private final LinkedHashMap<Long, PendingRequest> mPendingSmsMap = new LinkedHashMap<>();
133 
134     private long mWaitTimeForDatagramSendingResponse;
135     private long mWaitTimeForDatagramSendingForLastMessageResponse;
136     @SatelliteManager.DatagramType
137     private int mLastSendRequestDatagramType = DATAGRAM_TYPE_UNKNOWN;
138     @Nullable private PersistentLogger mPersistentLogger = null;
139 
140     @GuardedBy("mLock")
141     private int mModemState = SATELLITE_MODEM_STATE_UNKNOWN;
142     @GuardedBy("mLock")
143     private boolean mHasEnteredConnectedState = false;
144     @GuardedBy("mLock")
145     private boolean mShouldPollMtSms = false;
146     @GuardedBy("mLock")
147     private boolean mIsMtSmsPollingThrottled = false;
148     @GuardedBy("mLock")
149     private int mConnectedStateCounter = 0;
150     private long mSmsTransmissionStartTime = 0;
151 
152     /**
153      * Create the DatagramDispatcher singleton instance.
154      * @param context The Context to use to create the DatagramDispatcher.
155      * @param looper The looper for the handler.
156      * @param featureFlags The telephony feature flags.
157      * @param datagramController DatagramController which is used to update datagram transfer state.
158      * @return The singleton instance of DatagramDispatcher.
159      */
make(@onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags, @NonNull DatagramController datagramController)160     public static DatagramDispatcher make(@NonNull Context context, @NonNull Looper looper,
161             @NonNull FeatureFlags featureFlags,
162             @NonNull DatagramController datagramController) {
163         if (sInstance == null) {
164             sInstance = new DatagramDispatcher(context, looper, featureFlags, datagramController);
165         }
166         return sInstance;
167     }
168 
169     /**
170      * @return The singleton instance of DatagramDispatcher.
171      */
getInstance()172     public static DatagramDispatcher getInstance() {
173         if (sInstance == null) {
174             loge("DatagramDispatcher was not yet initialized.");
175         }
176         return sInstance;
177     }
178 
179     /**
180      * Create a DatagramDispatcher to send satellite datagrams.
181      *
182      * @param context The Context for the DatagramDispatcher.
183      * @param looper The looper for the handler.
184      * @param featureFlags The telephony feature flags.
185      * @param datagramController DatagramController which is used to update datagram transfer state.
186      */
187     @VisibleForTesting
DatagramDispatcher(@onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags, @NonNull DatagramController datagramController)188     protected DatagramDispatcher(@NonNull Context context, @NonNull Looper looper,
189             @NonNull FeatureFlags featureFlags,
190             @NonNull DatagramController datagramController) {
191         super(looper);
192         mContext = context;
193         mFeatureFlags = featureFlags;
194         mDatagramController = datagramController;
195         mControllerMetricsStats = ControllerMetricsStats.getInstance();
196         mSessionMetricsStats = SessionMetricsStats.getInstance();
197         mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
198 
199         synchronized (mLock) {
200             mSendingInProgress = false;
201         }
202         mWaitTimeForDatagramSendingResponse = getWaitForDatagramSendingResponseTimeoutMillis();
203         mWaitTimeForDatagramSendingForLastMessageResponse =
204                 getWaitForDatagramSendingResponseForLastMessageTimeoutMillis();
205     }
206 
207     private static final class DatagramDispatcherHandlerRequest {
208         /** The argument to use for the request */
209         public @NonNull Object argument;
210         /** The caller needs to specify the phone to be used for the request */
211         public @NonNull Phone phone;
212         /** The result of the request that is run on the main thread */
213         public @Nullable Object result;
214 
DatagramDispatcherHandlerRequest(Object argument, Phone phone)215         DatagramDispatcherHandlerRequest(Object argument, Phone phone) {
216             this.argument = argument;
217             this.phone = phone;
218         }
219     }
220 
221     private static final class SendSatelliteDatagramArgument {
222         public int subId;
223         public long datagramId;
224         public @SatelliteManager.DatagramType int datagramType;
225         public @NonNull SatelliteDatagram datagram;
226         public boolean needFullScreenPointingUI;
227         public @NonNull Consumer<Integer> callback;
228         public long datagramStartTime;
229         public boolean skipCheckingSatelliteAligned = false;
230 
SendSatelliteDatagramArgument(int subId, long datagramId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull Consumer<Integer> callback)231         SendSatelliteDatagramArgument(int subId, long datagramId,
232                 @SatelliteManager.DatagramType int datagramType,
233                 @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
234                 @NonNull Consumer<Integer> callback) {
235             this.subId = subId;
236             this.datagramId = datagramId;
237             this.datagramType = datagramType;
238             this.datagram = datagram;
239             this.needFullScreenPointingUI = needFullScreenPointingUI;
240             this.callback = callback;
241         }
242 
243         /** returns the size of outgoing SMS, rounded by 10 bytes */
getDatagramRoundedSizeBytes()244         public int getDatagramRoundedSizeBytes() {
245             if (datagram.getSatelliteDatagram() != null) {
246                 int sizeBytes = datagram.getSatelliteDatagram().length;
247                 // rounded by ROUNDING_UNIT
248                 return (int) (Math.round((double) sizeBytes / ROUNDING_UNIT) * ROUNDING_UNIT);
249             } else {
250                 return 0;
251             }
252         }
253 
254         /** sets the start time at datagram is sent out */
setDatagramStartTime()255         public void setDatagramStartTime() {
256             datagramStartTime =
257                     datagramStartTime == 0 ? System.currentTimeMillis() : datagramStartTime;
258         }
259     }
260 
261     @Override
handleMessage(Message msg)262     public void handleMessage(Message msg) {
263         DatagramDispatcherHandlerRequest request;
264         Message onCompleted;
265         AsyncResult ar;
266 
267         switch(msg.what) {
268             case CMD_SEND_SATELLITE_DATAGRAM: {
269                 plogd("CMD_SEND_SATELLITE_DATAGRAM mIsDemoMode=" + mIsDemoMode
270                         + ", shouldSendDatagramToModemInDemoMode="
271                         + shouldSendDatagramToModemInDemoMode());
272                 request = (DatagramDispatcherHandlerRequest) msg.obj;
273                 SendSatelliteDatagramArgument argument =
274                         (SendSatelliteDatagramArgument) request.argument;
275                 argument.setDatagramStartTime();
276                 onCompleted = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request);
277 
278                 synchronized (mLock) {
279                     if (mIsDemoMode && !shouldSendDatagramToModemInDemoMode()) {
280                         AsyncResult.forMessage(onCompleted, SATELLITE_RESULT_SUCCESS, null);
281                         sendMessageDelayed(onCompleted, getDemoTimeoutDuration());
282                     } else {
283                         SatelliteModemInterface.getInstance().sendSatelliteDatagram(
284                                 argument.datagram,
285                                 SatelliteServiceUtils.isSosMessage(argument.datagramType),
286                                 argument.needFullScreenPointingUI, onCompleted);
287                         startWaitForDatagramSendingResponseTimer(argument);
288                     }
289                 }
290                 break;
291             }
292             case EVENT_SEND_SATELLITE_DATAGRAM_DONE: {
293                 ar = (AsyncResult) msg.obj;
294                 request = (DatagramDispatcherHandlerRequest) ar.userObj;
295                 int error = SatelliteServiceUtils.getSatelliteError(ar, "sendDatagram");
296                 SendSatelliteDatagramArgument argument =
297                         (SendSatelliteDatagramArgument) request.argument;
298 
299                 synchronized (mLock) {
300                     if (mIsDemoMode && (error == SatelliteManager.SATELLITE_RESULT_SUCCESS)) {
301                         if (argument.skipCheckingSatelliteAligned) {
302                             plogd("Satellite was already aligned. "
303                                 + "No need to check alignment again");
304                         } else if (mDatagramController.waitForAligningToSatellite(mIsAligned)) {
305                             plogd("Satellite is not aligned in demo mode, wait for the alignment.");
306                             startSatelliteAlignedTimer(request);
307                             break;
308                         }
309                     }
310                     plogd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error
311                             + ", mIsDemoMode=" + mIsDemoMode);
312 
313                     /*
314                      * The response should be ignored if either of the following hold
315                      * 1) Framework has already received this response from the vendor service.
316                      * 2) Framework has timed out to wait for the response from vendor service for
317                      *    the send request.
318                      * 3) All pending send requests have been aborted due to some error.
319                      */
320                     if (!shouldProcessEventSendSatelliteDatagramDone(argument)) {
321                         plogw("The message " + argument.datagramId + " was already processed");
322                         break;
323                     }
324 
325                     stopWaitForDatagramSendingResponseTimer();
326                     mSendingInProgress = false;
327 
328                     // Log metrics about the outgoing datagram
329                     reportSendDatagramCompleted(argument, error);
330                     // Remove current datagram from pending map.
331                     if (SatelliteServiceUtils.isSosMessage(argument.datagramType)) {
332                         mPendingEmergencyDatagramsMap.remove(argument.datagramId);
333                         if (error == SATELLITE_RESULT_SUCCESS) {
334                             mIsEmergencyCommunicationEstablished = true;
335                         }
336                     } else {
337                         mPendingNonEmergencyDatagramsMap.remove(argument.datagramId);
338                     }
339 
340                     if (error == SATELLITE_RESULT_SUCCESS) {
341                         // Update send status for current datagram
342                         mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
343                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS,
344                                 getPendingMessagesCount(), error);
345                         startWaitForSimulatedPollDatagramsDelayTimer(request);
346                     } else {
347                         // Update send status
348                         mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
349                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
350                                 getPendingMessagesCount(), error);
351                     }
352 
353                     if (getPendingMessagesCount() > 0) {
354                         // Send response for current datagram
355                         argument.callback.accept(error);
356                         // Send pending datagrams
357                         sendPendingMessages();
358                     } else {
359                         mDatagramController.updateSendStatus(argument.subId,
360                                 argument.datagramType,
361                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0,
362                                 SatelliteManager.SATELLITE_RESULT_SUCCESS);
363                         // Send response for current datagram
364                         argument.callback.accept(error);
365                     }
366                 }
367                 break;
368             }
369 
370             case EVENT_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMED_OUT:
371                 handleEventWaitForDatagramSendingResponseTimedOut(
372                         (SendSatelliteDatagramArgument) msg.obj);
373                 break;
374 
375             case EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT: {
376                 handleEventSatelliteAlignedTimeout((DatagramDispatcherHandlerRequest) msg.obj);
377                 break;
378             }
379 
380             case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT:
381                 handleEventDatagramWaitForConnectedStateTimedOut((int) msg.obj);
382                 break;
383 
384             case EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT:
385                 request = (DatagramDispatcherHandlerRequest) msg.obj;
386                 handleEventWaitForSimulatedPollDatagramsDelayTimedOut(
387                         (SendSatelliteDatagramArgument) request.argument);
388                 break;
389 
390             case CMD_SEND_SMS: {
391                 PendingRequest pendingRequest = (PendingRequest) msg.obj;
392                 Phone satellitePhone = SatelliteController.getInstance().getSatellitePhone();
393                 if (satellitePhone == null) {
394                     ploge("CMD_SEND_SMS: satellitePhone is null.");
395                     return;
396                 }
397 
398                 SmsDispatchersController smsDispatchersController =
399                         satellitePhone.getSmsDispatchersController();
400                 if (smsDispatchersController == null) {
401                     ploge("CMD_SEND_SMS: smsDispatchersController is null.");
402                     return;
403                 }
404 
405                 mSmsTransmissionStartTime = System.currentTimeMillis();
406                 smsDispatchersController.sendCarrierRoamingNbIotNtnText(pendingRequest);
407                 break;
408             }
409 
410             case EVENT_SEND_SMS_DONE: {
411                 SomeArgs args = (SomeArgs) msg.obj;
412                 int subId = (int) args.arg1;
413                 long messageId = (long) args.arg2;
414                 boolean success = (boolean) args.arg3;
415                 try {
416                     handleEventSendSmsDone(subId, messageId, success);
417                 } finally {
418                     args.recycle();
419                 }
420                 break;
421             }
422 
423             case EVENT_MT_SMS_POLLING_THROTTLE_TIMED_OUT: {
424                 synchronized (mLock) {
425                     mIsMtSmsPollingThrottled = false;
426                 }
427                 if (allowMtSmsPolling()) {
428                     sendMessage(obtainMessage(CMD_SEND_MT_SMS_POLLING_MESSAGE));
429                 }
430                 break;
431             }
432 
433             case CMD_SEND_MT_SMS_POLLING_MESSAGE: {
434                 plogd("CMD_SEND_MT_SMS_POLLING_MESSAGE");
435                 handleCmdSendMtSmsPollingMessage();
436                 break;
437             }
438 
439             default:
440                 plogw("DatagramDispatcherHandler: unexpected message code: " + msg.what);
441                 break;
442         }
443     }
444 
445     /**
446      * Send datagram over satellite.
447      *
448      * Gateway encodes SOS message or location sharing message into a datagram and passes it as
449      * input to this method. Datagram received here will be passed down to modem without any
450      * encoding or encryption.
451      *
452      * @param subId The subId of the subscription to send satellite datagrams for.
453      * @param datagramType datagram type indicating whether the datagram is of type
454      *                     SOS_SMS or LOCATION_SHARING.
455      * @param datagram encoded gateway datagram which is encrypted by the caller.
456      *                 Datagram will be passed down to modem without any encoding or encryption.
457      * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in
458      *                                 full screen mode.
459      * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request.
460      */
sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull Consumer<Integer> callback)461     public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType,
462             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
463             @NonNull Consumer<Integer> callback) {
464         Phone phone = SatelliteServiceUtils.getPhone();
465 
466         long datagramId = mNextDatagramId.getAndUpdate(
467                 n -> ((n + 1) % DatagramController.MAX_DATAGRAM_ID));
468         SendSatelliteDatagramArgument datagramArgs =
469                 new SendSatelliteDatagramArgument(subId, datagramId, datagramType, datagram,
470                         needFullScreenPointingUI, callback);
471         mLastSendRequestDatagramType = datagramType;
472 
473         synchronized (mLock) {
474             // Add datagram to pending datagram map
475             if (SatelliteServiceUtils.isSosMessage(datagramType)) {
476                 mPendingEmergencyDatagramsMap.put(datagramId, datagramArgs);
477             } else {
478                 mPendingNonEmergencyDatagramsMap.put(datagramId, datagramArgs);
479             }
480 
481             if (mDatagramController.needsWaitingForSatelliteConnected(datagramType)) {
482                 plogd("sendDatagram: wait for satellite connected");
483                 mDatagramController.updateSendStatus(subId, datagramType,
484                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
485                         getPendingMessagesCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
486                 startDatagramWaitForConnectedStateTimer(datagramArgs.datagramType);
487             } else if (!mSendingInProgress && mDatagramController.isPollingInIdleState()) {
488                 // Modem can be busy receiving datagrams, so send datagram only when modem is
489                 // not busy.
490                 mSendingInProgress = true;
491                 mDatagramController.updateSendStatus(subId, datagramType,
492                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
493                         getPendingMessagesCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
494                 sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone);
495             } else {
496                 plogd("sendDatagram: mSendingInProgress=" + mSendingInProgress
497                         + ", isPollingInIdleState=" + mDatagramController.isPollingInIdleState());
498             }
499         }
500     }
501 
retrySendingDatagrams()502     public void retrySendingDatagrams() {
503         synchronized (mLock) {
504             sendPendingMessages();
505         }
506     }
507 
508     /** Set demo mode
509      *
510      * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise.
511      */
512     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
setDemoMode(boolean isDemoMode)513     protected void setDemoMode(boolean isDemoMode) {
514         mIsDemoMode = isDemoMode;
515         plogd("setDemoMode: mIsDemoMode=" + mIsDemoMode);
516     }
517 
518     /**
519      * Set whether the device is aligned with the satellite.
520      */
521     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
setDeviceAlignedWithSatellite(boolean isAligned)522     public void setDeviceAlignedWithSatellite(boolean isAligned) {
523         synchronized (mLock) {
524             mIsAligned = isAligned;
525             plogd("setDeviceAlignedWithSatellite: " + mIsAligned);
526             if (isAligned && mIsDemoMode) handleEventSatelliteAligned();
527         }
528         if (allowMtSmsPolling()) {
529             sendMessage(obtainMessage(CMD_SEND_MT_SMS_POLLING_MESSAGE));
530         }
531     }
532 
startSatelliteAlignedTimer(@onNull DatagramDispatcherHandlerRequest request)533     private void startSatelliteAlignedTimer(@NonNull DatagramDispatcherHandlerRequest request) {
534         if (isSatelliteAlignedTimerStarted()) {
535             plogd("Satellite aligned timer was already started");
536             return;
537         }
538         mSendSatelliteDatagramRequest = request;
539         sendMessageDelayed(
540                 obtainMessage(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT, request),
541                 getSatelliteAlignedTimeoutDuration());
542     }
543 
544     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
getSatelliteAlignedTimeoutDuration()545     protected long getSatelliteAlignedTimeoutDuration() {
546         return mDatagramController.getSatelliteAlignedTimeoutDuration();
547     }
548 
handleEventSatelliteAligned()549     private void handleEventSatelliteAligned() {
550         if (isSatelliteAlignedTimerStarted()) {
551             stopSatelliteAlignedTimer();
552 
553             if (mSendSatelliteDatagramRequest == null) {
554                 ploge("handleEventSatelliteAligned: mSendSatelliteDatagramRequest is null");
555             } else {
556                 SendSatelliteDatagramArgument argument =
557                         (SendSatelliteDatagramArgument) mSendSatelliteDatagramRequest.argument;
558                 argument.skipCheckingSatelliteAligned = true;
559                 Message message = obtainMessage(
560                         EVENT_SEND_SATELLITE_DATAGRAM_DONE, mSendSatelliteDatagramRequest);
561                 mSendSatelliteDatagramRequest = null;
562                 AsyncResult.forMessage(message, null, null);
563                 message.sendToTarget();
564                 plogd("handleEventSatelliteAligned: EVENT_SEND_SATELLITE_DATAGRAM_DONE");
565             }
566         }
567     }
568 
handleEventSatelliteAlignedTimeout( @onNull DatagramDispatcherHandlerRequest request)569     private void handleEventSatelliteAlignedTimeout(
570             @NonNull DatagramDispatcherHandlerRequest request) {
571         plogd("handleEventSatelliteAlignedTimeout");
572         mSendSatelliteDatagramRequest = null;
573         SatelliteManager.SatelliteException exception =
574                 new SatelliteManager.SatelliteException(
575                         SATELLITE_RESULT_NOT_REACHABLE);
576         Message message = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request);
577         AsyncResult.forMessage(message, null, exception);
578         message.sendToTarget();
579     }
580 
isSatelliteAlignedTimerStarted()581     private boolean isSatelliteAlignedTimerStarted() {
582         return hasMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT);
583     }
584 
stopSatelliteAlignedTimer()585     private void stopSatelliteAlignedTimer() {
586         removeMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT);
587     }
588 
589     @GuardedBy("mLock")
sendPendingMessages()590     private void sendPendingMessages() {
591         plogd("sendPendingMessages");
592 
593         // Pending datagrams are prioritized over pending SMS.
594         if (getPendingDatagramCount() > 0) {
595             sendPendingDatagrams();
596             return;
597         }
598 
599         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
600             if (getPendingSmsCount() > 0) {
601                 sendPendingSms();
602             }
603         }
604     }
605 
606     /**
607      * Send pending satellite datagrams. Emergency datagrams are given priority over
608      * non-emergency datagrams.
609      */
610     @GuardedBy("mLock")
sendPendingDatagrams()611     private void sendPendingDatagrams() {
612         plogd("sendPendingDatagrams()");
613         if (!mDatagramController.isPollingInIdleState()) {
614             // Datagram should be sent to satellite modem when modem is free.
615             plogd("sendPendingDatagrams: modem is receiving datagrams");
616             return;
617         }
618 
619         if (getPendingDatagramCount() <= 0) {
620             plogd("sendPendingDatagrams: no pending datagrams to send");
621             return;
622         }
623 
624         Phone phone = SatelliteServiceUtils.getPhone();
625         Set<Entry<Long, SendSatelliteDatagramArgument>> pendingDatagram = null;
626         if (!mSendingInProgress && !mPendingEmergencyDatagramsMap.isEmpty()) {
627             pendingDatagram = mPendingEmergencyDatagramsMap.entrySet();
628         } else if (!mSendingInProgress && !mPendingNonEmergencyDatagramsMap.isEmpty()) {
629             pendingDatagram = mPendingNonEmergencyDatagramsMap.entrySet();
630         }
631 
632         if ((pendingDatagram != null) && pendingDatagram.iterator().hasNext()) {
633             SendSatelliteDatagramArgument datagramArg =
634                     pendingDatagram.iterator().next().getValue();
635             if (mDatagramController.needsWaitingForSatelliteConnected(datagramArg.datagramType)) {
636                 plogd("sendPendingDatagrams: wait for satellite connected");
637                 mDatagramController.updateSendStatus(datagramArg.subId,
638                         datagramArg.datagramType,
639                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
640                         getPendingMessagesCount(),
641                         SatelliteManager.SATELLITE_RESULT_SUCCESS);
642                 startDatagramWaitForConnectedStateTimer(
643                         datagramArg.datagramType);
644                 return;
645             }
646 
647             mSendingInProgress = true;
648             // Sets the trigger time for getting pending datagrams
649             mDatagramController.updateSendStatus(datagramArg.subId, datagramArg.datagramType,
650                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
651                     getPendingMessagesCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
652             sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArg, phone);
653         }
654     }
655 
656     /**
657      * Send error code to all the pending datagrams
658      *
659      * @param pendingDatagramsMap The pending datagrams map to be cleaned up.
660      * @param errorCode error code to be returned.
661      */
662     @GuardedBy("mLock")
sendErrorCodeAndCleanupPendingDatagrams( LinkedHashMap<Long, SendSatelliteDatagramArgument> pendingDatagramsMap, @SatelliteManager.SatelliteResult int errorCode)663     private void sendErrorCodeAndCleanupPendingDatagrams(
664             LinkedHashMap<Long, SendSatelliteDatagramArgument> pendingDatagramsMap,
665             @SatelliteManager.SatelliteResult int errorCode) {
666         if (pendingDatagramsMap.size() == 0) {
667             return;
668         }
669         ploge("sendErrorCodeAndCleanupPendingDatagrams: cleaning up resources");
670 
671         // Send error code to all the pending datagrams
672         for (Entry<Long, SendSatelliteDatagramArgument> entry :
673                 pendingDatagramsMap.entrySet()) {
674             SendSatelliteDatagramArgument argument = entry.getValue();
675             reportSendDatagramCompleted(argument, errorCode);
676             argument.callback.accept(errorCode);
677         }
678 
679         // Clear pending datagram maps
680         pendingDatagramsMap.clear();
681     }
682 
683     /**
684      * Abort sending all the pending datagrams.
685      *
686      * @param subId The subId of the subscription used to send datagram
687      * @param errorCode The error code that resulted in abort.
688      */
689     @GuardedBy("mLock")
abortSendingPendingDatagrams(int subId, @SatelliteManager.SatelliteResult int errorCode)690     private void abortSendingPendingDatagrams(int subId,
691             @SatelliteManager.SatelliteResult int errorCode) {
692         plogd("abortSendingPendingDatagrams()");
693         sendErrorCodeAndCleanupPendingDatagrams(mPendingEmergencyDatagramsMap, errorCode);
694         sendErrorCodeAndCleanupPendingDatagrams(mPendingNonEmergencyDatagramsMap, errorCode);
695         sendErrorCodeAndCleanupPendingSms(mPendingSmsMap, errorCode);
696     }
697 
698     /**
699      * Return pending datagram and SMS count
700      * @return pending messages count
701      */
getPendingMessagesCount()702     public int getPendingMessagesCount() {
703         synchronized (mLock) {
704             if (mFeatureFlags.carrierRoamingNbIotNtn()) {
705                 return getPendingDatagramCount() + getPendingSmsCount();
706             } else {
707                 return getPendingDatagramCount();
708             }
709         }
710     }
711 
712     /**
713      * Return pending datagram count
714      * @return pending datagram count
715      */
getPendingDatagramCount()716     public int getPendingDatagramCount() {
717         synchronized (mLock) {
718             return mPendingEmergencyDatagramsMap.size() + mPendingNonEmergencyDatagramsMap.size();
719         }
720     }
721 
722     /**
723      * Return pending SMS count
724      * @return pending SMS count
725      */
getPendingSmsCount()726     public int getPendingSmsCount() {
727         synchronized (mLock) {
728             return mPendingSmsMap.size();
729         }
730     }
731 
732     /** Return pending user messages count */
getPendingUserMessagesCount()733     public int getPendingUserMessagesCount() {
734         synchronized (mLock) {
735             int pendingUserMessagesCount = 0;
736             for (Entry<Long, SendSatelliteDatagramArgument> entry :
737                     mPendingNonEmergencyDatagramsMap.entrySet()) {
738                 SendSatelliteDatagramArgument argument = entry.getValue();
739                 if (argument.datagramType != SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE) {
740                     pendingUserMessagesCount += 1;
741                 }
742             }
743             pendingUserMessagesCount += mPendingEmergencyDatagramsMap.size();
744             return pendingUserMessagesCount;
745         }
746     }
747 
748     /**
749      * Posts the specified command to be executed on the main thread and returns immediately.
750      *
751      * @param command command to be executed on the main thread
752      * @param argument additional parameters required to perform of the operation
753      * @param phone phone object used to perform the operation.
754      */
sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone)755     private void sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone) {
756         DatagramDispatcherHandlerRequest request = new DatagramDispatcherHandlerRequest(
757                 argument, phone);
758         Message msg = this.obtainMessage(command, request);
759         msg.sendToTarget();
760     }
761 
reportSendSmsCompleted(@onNull PendingRequest pendingRequest, @SatelliteManager.SatelliteResult int resultCode)762     private void reportSendSmsCompleted(@NonNull PendingRequest pendingRequest,
763             @SatelliteManager.SatelliteResult int resultCode) {
764         int datagramType = pendingRequest.isMtSmsPolling
765                 ? DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS : DATAGRAM_TYPE_SMS;
766         if (resultCode == SATELLITE_RESULT_SUCCESS) {
767             long smsTransmissionTime = mSmsTransmissionStartTime > 0
768                     ? (System.currentTimeMillis() - mSmsTransmissionStartTime) : 0;
769             mControllerMetricsStats.reportOutgoingDatagramSuccessCount(datagramType, false);
770             mSessionMetricsStats.addCountOfSuccessfulOutgoingDatagram(
771                     datagramType, smsTransmissionTime);
772         } else {
773             mControllerMetricsStats.reportOutgoingDatagramFailCount(datagramType, false);
774             mSessionMetricsStats.addCountOfFailedOutgoingDatagram(
775                     datagramType, resultCode);
776         }
777     }
778 
reportSendDatagramCompleted(@onNull SendSatelliteDatagramArgument argument, @NonNull @SatelliteManager.SatelliteResult int resultCode)779     private void reportSendDatagramCompleted(@NonNull SendSatelliteDatagramArgument argument,
780             @NonNull @SatelliteManager.SatelliteResult int resultCode) {
781         long datagramTransmissionTime = argument.datagramStartTime > 0
782                 ? (System.currentTimeMillis() - argument.datagramStartTime) : 0;
783         SatelliteStats.getInstance().onSatelliteOutgoingDatagramMetrics(
784                 new SatelliteStats.SatelliteOutgoingDatagramParams.Builder()
785                         .setDatagramType(argument.datagramType)
786                         .setResultCode(resultCode)
787                         .setDatagramSizeBytes(argument.getDatagramRoundedSizeBytes())
788                         /* In case pending datagram has not been attempted to send to modem
789                         interface. transfer time will be 0. */
790                         .setDatagramTransferTimeMillis(datagramTransmissionTime)
791                         .setIsDemoMode(mIsDemoMode)
792                         .setCarrierId(SatelliteController.getInstance().getSatelliteCarrierId())
793                         .setIsNtnOnlyCarrier(SatelliteController.getInstance().isNtnOnlyCarrier())
794                         .build());
795         if (resultCode == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
796             mControllerMetricsStats.reportOutgoingDatagramSuccessCount(argument.datagramType,
797                     mIsDemoMode);
798             mSessionMetricsStats.addCountOfSuccessfulOutgoingDatagram(argument.datagramType,
799                     datagramTransmissionTime);
800         } else {
801             mControllerMetricsStats.reportOutgoingDatagramFailCount(argument.datagramType,
802                     mIsDemoMode);
803             mSessionMetricsStats.addCountOfFailedOutgoingDatagram(argument.datagramType,
804                     resultCode);
805         }
806     }
807 
808     /**
809      * Destroys this DatagramDispatcher. Used for tearing down static resources during testing.
810      */
811     @VisibleForTesting
destroy()812     public void destroy() {
813         sInstance = null;
814     }
815 
816     /**
817      * This function is used by {@link DatagramController} to notify {@link DatagramDispatcher}
818      * that satellite modem state has changed.
819      *
820      * @param state Current satellite modem state.
821      */
onSatelliteModemStateChanged(@atelliteManager.SatelliteModemState int state)822     public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) {
823         synchronized (mLock) {
824             mModemState = state;
825             if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF
826                     || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) {
827                 plogd("onSatelliteModemStateChanged: cleaning up resources");
828                 cleanUpResources();
829             } else if (state == SatelliteManager.SATELLITE_MODEM_STATE_IDLE) {
830                 sendPendingMessages();
831             }
832 
833             if (state == SATELLITE_MODEM_STATE_CONNECTED) {
834                 mHasEnteredConnectedState = true;
835 
836                 mConnectedStateCounter++;
837                 if (isFirstConnected()) {
838                     mShouldPollMtSms = shouldPollMtSms();
839                 }
840 
841                 if (isDatagramWaitForConnectedStateTimerStarted()) {
842                     stopDatagramWaitForConnectedStateTimer();
843                     sendPendingMessages();
844                 }
845             }
846 
847             if (state == SATELLITE_MODEM_STATE_NOT_CONNECTED) {
848                 if (mHasEnteredConnectedState) {
849                     mHasEnteredConnectedState = false;
850                     mShouldPollMtSms = shouldPollMtSms();
851                 }
852             }
853         }
854         if (allowMtSmsPolling()) {
855             sendMessage(obtainMessage(CMD_SEND_MT_SMS_POLLING_MESSAGE));
856         }
857     }
858 
859     /** Returns true if this is the first time the satellite modem is connected. */
isFirstConnected()860     private boolean isFirstConnected() {
861         return mConnectedStateCounter == 1;
862     }
863 
864     @GuardedBy("mLock")
cleanUpResources()865     private void cleanUpResources() {
866         plogd("cleanUpResources");
867         mSendingInProgress = false;
868         mIsEmergencyCommunicationEstablished = false;
869 
870         int subId = SatelliteController.getInstance().getSelectedSatelliteSubId();
871         if (getPendingMessagesCount() > 0) {
872             mDatagramController.updateSendStatus(subId,
873                     mLastSendRequestDatagramType,
874                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
875                     getPendingMessagesCount(), SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED);
876         }
877         mDatagramController.updateSendStatus(subId,
878                 mLastSendRequestDatagramType,
879                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
880                 0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
881         abortSendingPendingDatagrams(subId,
882                 SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED);
883 
884         stopSatelliteAlignedTimer();
885         stopDatagramWaitForConnectedStateTimer();
886         stopWaitForDatagramSendingResponseTimer();
887         stopWaitForSimulatedPollDatagramsDelayTimer();
888         mIsDemoMode = false;
889         mSendSatelliteDatagramRequest = null;
890         mIsAligned = false;
891         mLastSendRequestDatagramType = DATAGRAM_TYPE_UNKNOWN;
892         mModemState = SATELLITE_MODEM_STATE_UNKNOWN;
893         mHasEnteredConnectedState = false;
894         mShouldPollMtSms = false;
895         mConnectedStateCounter = 0;
896         stopMtSmsPollingThrottle();
897     }
898 
899     /** @return {@code true} if already sent an emergency datagram during a session. */
isEmergencyCommunicationEstablished()900     public boolean isEmergencyCommunicationEstablished() {
901         synchronized (mLock) {
902             return mIsEmergencyCommunicationEstablished;
903         }
904     }
905 
startDatagramWaitForConnectedStateTimer( @atelliteManager.DatagramType int datagramType)906     private void startDatagramWaitForConnectedStateTimer(
907             @SatelliteManager.DatagramType int datagramType) {
908         if (isDatagramWaitForConnectedStateTimerStarted()) {
909             plogd("DatagramWaitForConnectedStateTimer is already started");
910             return;
911         }
912         sendMessageDelayed(obtainMessage(
913                         EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT, datagramType),
914                 mDatagramController.getDatagramWaitTimeForConnectedState(
915                         SatelliteServiceUtils.isLastSosMessage(datagramType)));
916     }
917 
stopDatagramWaitForConnectedStateTimer()918     private void stopDatagramWaitForConnectedStateTimer() {
919         removeMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT);
920     }
921 
922     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
isDatagramWaitForConnectedStateTimerStarted()923     public boolean isDatagramWaitForConnectedStateTimerStarted() {
924         return hasMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT);
925     }
926 
927     /**
928      * This API is used by CTS tests to override the mWaitTimeForDatagramSendingResponse.
929      */
setWaitTimeForDatagramSendingResponse(boolean reset, long timeoutMillis)930     void setWaitTimeForDatagramSendingResponse(boolean reset, long timeoutMillis) {
931         if (reset) {
932             mWaitTimeForDatagramSendingResponse = getWaitForDatagramSendingResponseTimeoutMillis();
933         } else {
934             mWaitTimeForDatagramSendingResponse = timeoutMillis;
935         }
936     }
937 
startWaitForDatagramSendingResponseTimer( @onNull SendSatelliteDatagramArgument argument)938     private void startWaitForDatagramSendingResponseTimer(
939             @NonNull SendSatelliteDatagramArgument argument) {
940         if (hasMessages(EVENT_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMED_OUT)) {
941             plogd("WaitForDatagramSendingResponseTimer was already started");
942             return;
943         }
944         long waitTime = SatelliteServiceUtils.isLastSosMessage(argument.datagramType)
945                 ? mWaitTimeForDatagramSendingForLastMessageResponse
946                 : mWaitTimeForDatagramSendingResponse;
947         logd("startWaitForDatagramSendingResponseTimer: datagramType=" + argument.datagramType
948                 + ", waitTime=" + waitTime);
949         sendMessageDelayed(obtainMessage(
950                 EVENT_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMED_OUT, argument), waitTime);
951     }
952 
stopWaitForDatagramSendingResponseTimer()953     private void stopWaitForDatagramSendingResponseTimer() {
954         removeMessages(EVENT_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMED_OUT);
955     }
956 
handleEventDatagramWaitForConnectedStateTimedOut( @atelliteManager.DatagramType int datagramType)957     private void handleEventDatagramWaitForConnectedStateTimedOut(
958             @SatelliteManager.DatagramType int datagramType) {
959         plogw("Timed out to wait for satellite connected before sending datagrams");
960         synchronized (mLock) {
961             int subId = SatelliteController.getInstance().getSelectedSatelliteSubId();
962             // Update send status
963             mDatagramController.updateSendStatus(subId,
964                     datagramType,
965                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
966                     getPendingMessagesCount(),
967                     SATELLITE_RESULT_NOT_REACHABLE);
968             mDatagramController.updateSendStatus(subId,
969                     datagramType,
970                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
971                     0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
972             abortSendingPendingDatagrams(subId,
973                     SATELLITE_RESULT_NOT_REACHABLE);
974         }
975     }
976 
shouldSendDatagramToModemInDemoMode()977     private boolean shouldSendDatagramToModemInDemoMode() {
978         if (mShouldSendDatagramToModemInDemoMode != null) {
979             return mShouldSendDatagramToModemInDemoMode.get();
980         }
981 
982         try {
983             mShouldSendDatagramToModemInDemoMode = new AtomicBoolean(
984                     mContext.getResources().getBoolean(
985                             R.bool.config_send_satellite_datagram_to_modem_in_demo_mode));
986             return mShouldSendDatagramToModemInDemoMode.get();
987 
988         } catch (Resources.NotFoundException ex) {
989             ploge("shouldSendDatagramToModemInDemoMode: id= "
990                     + R.bool.config_send_satellite_datagram_to_modem_in_demo_mode + ", ex=" + ex);
991             return false;
992         }
993     }
994 
getWaitForDatagramSendingResponseTimeoutMillis()995     private long getWaitForDatagramSendingResponseTimeoutMillis() {
996         return mContext.getResources().getInteger(
997                 R.integer.config_wait_for_datagram_sending_response_timeout_millis);
998     }
999 
getWaitForDatagramSendingResponseForLastMessageTimeoutMillis()1000     private long getWaitForDatagramSendingResponseForLastMessageTimeoutMillis() {
1001         return mContext.getResources().getInteger(R.integer
1002                 .config_wait_for_datagram_sending_response_for_last_message_timeout_millis);
1003     }
1004 
shouldProcessEventSendSatelliteDatagramDone( @onNull SendSatelliteDatagramArgument argument)1005     private boolean shouldProcessEventSendSatelliteDatagramDone(
1006             @NonNull SendSatelliteDatagramArgument argument) {
1007         synchronized (mLock) {
1008             if (SatelliteServiceUtils.isSosMessage(argument.datagramType)) {
1009                 return mPendingEmergencyDatagramsMap.containsKey(argument.datagramId);
1010             } else {
1011                 return mPendingNonEmergencyDatagramsMap.containsKey(argument.datagramId);
1012             }
1013         }
1014     }
1015 
handleEventWaitForDatagramSendingResponseTimedOut( @onNull SendSatelliteDatagramArgument argument)1016     private void handleEventWaitForDatagramSendingResponseTimedOut(
1017             @NonNull SendSatelliteDatagramArgument argument) {
1018         synchronized (mLock) {
1019             plogw("Timed out to wait for the response of the request to send the datagram "
1020                     + argument.datagramId);
1021 
1022             // Ask vendor service to abort all datagram-sending requests
1023             SatelliteModemInterface.getInstance().abortSendingSatelliteDatagrams(
1024                     obtainMessage(EVENT_ABORT_SENDING_SATELLITE_DATAGRAMS_DONE, argument));
1025             mSendingInProgress = false;
1026 
1027             // Update send status
1028             mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
1029                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
1030                     getPendingMessagesCount(), SATELLITE_RESULT_MODEM_TIMEOUT);
1031             mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
1032                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
1033                     0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
1034 
1035             // Send response for current datagram after updating datagram transfer state
1036             // internally.
1037             argument.callback.accept(SATELLITE_RESULT_MODEM_TIMEOUT);
1038 
1039             // Log metrics about the outgoing datagram
1040             reportSendDatagramCompleted(argument, SATELLITE_RESULT_MODEM_TIMEOUT);
1041             // Remove current datagram from pending map.
1042             if (SatelliteServiceUtils.isSosMessage(argument.datagramType)) {
1043                 mPendingEmergencyDatagramsMap.remove(argument.datagramId);
1044             } else {
1045                 mPendingNonEmergencyDatagramsMap.remove(argument.datagramId);
1046             }
1047 
1048             // Abort sending all the pending datagrams
1049             abortSendingPendingDatagrams(argument.subId, SATELLITE_RESULT_MODEM_TIMEOUT);
1050         }
1051     }
1052 
1053     /**
1054      * This API can be used by only CTS to override the cached value for the device overlay config
1055      * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether
1056      * outgoing satellite datagrams should be sent to modem in demo mode.
1057      *
1058      * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to
1059      * satellite modem or not. If it is null, the cache will be cleared.
1060      */
1061     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
setShouldSendDatagramToModemInDemoMode( @ullable Boolean shouldSendToModemInDemoMode)1062     protected void setShouldSendDatagramToModemInDemoMode(
1063             @Nullable Boolean shouldSendToModemInDemoMode) {
1064         plogd("setShouldSendDatagramToModemInDemoMode(" + (shouldSendToModemInDemoMode == null
1065                 ? "null" : shouldSendToModemInDemoMode) + ")");
1066 
1067         if (shouldSendToModemInDemoMode == null) {
1068             mShouldSendDatagramToModemInDemoMode = null;
1069         } else {
1070             if (mShouldSendDatagramToModemInDemoMode == null) {
1071                 mShouldSendDatagramToModemInDemoMode = new AtomicBoolean(
1072                         shouldSendToModemInDemoMode);
1073             } else {
1074                 mShouldSendDatagramToModemInDemoMode.set(shouldSendToModemInDemoMode);
1075             }
1076         }
1077     }
1078 
startWaitForSimulatedPollDatagramsDelayTimer( @onNull DatagramDispatcherHandlerRequest request)1079     private void startWaitForSimulatedPollDatagramsDelayTimer(
1080             @NonNull DatagramDispatcherHandlerRequest request) {
1081         if (mIsDemoMode) {
1082             plogd("startWaitForSimulatedPollDatagramsDelayTimer");
1083             sendMessageDelayed(
1084                     obtainMessage(EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT, request),
1085                     getDemoTimeoutDuration());
1086         } else {
1087             plogd("Should not start WaitForSimulatedPollDatagramsDelayTimer in non-demo mode");
1088         }
1089     }
1090 
stopWaitForSimulatedPollDatagramsDelayTimer()1091     private void stopWaitForSimulatedPollDatagramsDelayTimer() {
1092         removeMessages(EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT);
1093     }
1094 
handleEventWaitForSimulatedPollDatagramsDelayTimedOut( @onNull SendSatelliteDatagramArgument argument)1095     private void handleEventWaitForSimulatedPollDatagramsDelayTimedOut(
1096             @NonNull SendSatelliteDatagramArgument argument) {
1097         if (mIsDemoMode) {
1098             plogd("handleEventWaitForSimulatedPollDatagramsDelayTimedOut");
1099             mDatagramController.pushDemoModeDatagram(argument.datagramType, argument.datagram);
1100             Consumer<Integer> internalCallback = new Consumer<Integer>() {
1101                 @Override
1102                 public void accept(Integer result) {
1103                     plogd("pollPendingSatelliteDatagrams result: " + result);
1104                 }
1105             };
1106             mDatagramController.pollPendingSatelliteDatagrams(argument.subId, internalCallback);
1107         } else {
1108             plogd("Unexpected EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT in "
1109                     + "non-demo mode");
1110         }
1111     }
1112 
getDemoTimeoutDuration()1113     long getDemoTimeoutDuration() {
1114         return mDemoTimeoutDuration;
1115     }
1116 
1117     /**
1118      * This API is used by CTS tests to override the mDemoTimeoutDuration.
1119      */
setTimeoutDatagramDelayInDemoMode(boolean reset, long timeoutMillis)1120     void setTimeoutDatagramDelayInDemoMode(boolean reset, long timeoutMillis) {
1121         if (!mIsDemoMode) {
1122             return;
1123         }
1124         if (reset) {
1125             mDemoTimeoutDuration = TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE;
1126         } else {
1127             mDemoTimeoutDuration = timeoutMillis;
1128         }
1129         plogd("setTimeoutDatagramDelayInDemoMode " + mDemoTimeoutDuration + " reset=" + reset);
1130     }
1131 
1132     /**
1133      * Send carrier roaming nb iot ntn sms.
1134      *
1135      * Store SMS in a pending list until following conditions are met:
1136      * - If messages can be sent only when satellite is connected, then wait until modem state
1137      * becomes {@link SatelliteManager#SATELLITE_MODEM_STATE_CONNECTED}
1138      * - If modem is already sending datagrms/SMS or receiving datagrams, then wait until modem
1139      * becomes IDLE to send current SMS.
1140      *
1141      * @param pendingSms {@link PendingRequest} that contains all the information required to send
1142      *                    carrier roaming nb iot ntn SMS.
1143      */
sendSms(@onNull PendingRequest pendingSms)1144     public void sendSms(@NonNull PendingRequest pendingSms) {
1145         SatelliteController.getInstance().startPointingUI();
1146 
1147         int subId = SatelliteController.getInstance().getSelectedSatelliteSubId();
1148         long messageId = pendingSms.uniqueMessageId;
1149         plogd("sendSms: subId=" + subId + " messageId:" + messageId);
1150 
1151         synchronized (mLock) {
1152             // Add SMS to pending list
1153             mPendingSmsMap.put(messageId, pendingSms);
1154             int datagramType = pendingSms.isMtSmsPolling ?
1155                     DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS : DATAGRAM_TYPE_SMS;
1156             mLastSendRequestDatagramType = datagramType;
1157 
1158             if (mDatagramController.needsWaitingForSatelliteConnected(datagramType)) {
1159                 plogd("sendSms: wait for satellite connected");
1160                 mDatagramController.updateSendStatus(subId, datagramType,
1161                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
1162                         getPendingMessagesCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
1163                 startDatagramWaitForConnectedStateTimer(datagramType);
1164             } else if (!mSendingInProgress && mDatagramController.isPollingInIdleState()) {
1165                 mSendingInProgress = true;
1166                 mDatagramController.updateSendStatus(subId, datagramType,
1167                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
1168                         getPendingMessagesCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
1169 
1170                 sendMessage(obtainMessage(CMD_SEND_SMS, pendingSms));
1171             } else {
1172                 plogd("sendSms: mSendingInProgress=" + mSendingInProgress
1173                         + ", isPollingInIdleState=" + mDatagramController.isPollingInIdleState());
1174             }
1175         }
1176     }
1177 
1178     @GuardedBy("mLock")
sendPendingSms()1179     private void sendPendingSms() {
1180         plogd("sendPendingSms");
1181         if (!mDatagramController.isPollingInIdleState()) {
1182             // Datagram or SMS should be sent to satellite modem when modem is free.
1183             plogd("sendPendingSms: modem is receiving datagrams");
1184             return;
1185         }
1186 
1187         int subId = SatelliteController.getInstance().getSelectedSatelliteSubId();
1188         Set<Entry<Long, PendingRequest>> pendingSms = null;
1189         if (!mSendingInProgress) {
1190             pendingSms = mPendingSmsMap.entrySet();
1191         }
1192 
1193         if (pendingSms != null && pendingSms.iterator().hasNext()) {
1194             PendingRequest pendingRequest = pendingSms.iterator().next().getValue();
1195             int datagramType = pendingRequest.isMtSmsPolling
1196                     ? DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS : DATAGRAM_TYPE_SMS;
1197             if (mDatagramController.needsWaitingForSatelliteConnected(DATAGRAM_TYPE_SMS)) {
1198                 plogd("sendPendingSms: wait for satellite connected");
1199                 mDatagramController.updateSendStatus(subId,
1200                         datagramType,
1201                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
1202                         getPendingMessagesCount(),
1203                         SatelliteManager.SATELLITE_RESULT_SUCCESS);
1204                 startDatagramWaitForConnectedStateTimer(datagramType);
1205                 return;
1206             }
1207 
1208             mSendingInProgress = true;
1209             mDatagramController.updateSendStatus(subId,
1210                     datagramType,
1211                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
1212                     getPendingMessagesCount(), SATELLITE_RESULT_SUCCESS);
1213             sendMessage(obtainMessage(CMD_SEND_SMS, pendingRequest));
1214         } else {
1215             plogd("sendPendingSms: mSendingInProgress=" + mSendingInProgress
1216                     + " pendingSmsCount=" + getPendingSmsCount());
1217         }
1218     }
1219 
1220     /**
1221      * Sending MO SMS is completed.
1222      * @param subId subscription ID
1223      * @param messageId message ID of MO SMS
1224      * @param success boolean specifying whether MO SMS is successfully sent or not.
1225      */
onSendSmsDone(int subId, long messageId, boolean success)1226     public void onSendSmsDone(int subId, long messageId, boolean success) {
1227         SomeArgs args = SomeArgs.obtain();
1228         args.arg1 = subId;
1229         args.arg2 = messageId;
1230         args.arg3 = success;
1231         sendMessage(obtainMessage(EVENT_SEND_SMS_DONE, args));
1232     }
1233 
1234     @GuardedBy("mLock")
sendErrorCodeAndCleanupPendingSms( LinkedHashMap<Long, PendingRequest> pendingSmsMap, @SatelliteManager.SatelliteResult int errorCode)1235     private void sendErrorCodeAndCleanupPendingSms(
1236             LinkedHashMap<Long, PendingRequest> pendingSmsMap,
1237             @SatelliteManager.SatelliteResult int errorCode) {
1238         if (pendingSmsMap.size() == 0) {
1239             plogd("sendErrorCodeAndCleanupPendingSms: pendingSmsMap is empty.");
1240             return;
1241         }
1242         ploge("sendErrorCodeAndCleanupPendingSms: cleaning up resources. "
1243                 + "pendingSmsMap size=" + getPendingSmsCount());
1244 
1245         Phone satellitePhone = SatelliteController.getInstance().getSatellitePhone();
1246         if (satellitePhone == null) {
1247             ploge("sendErrorCodeAndCleanupPendingSms: satellitePhone is null.");
1248             pendingSmsMap.clear();
1249             return;
1250         }
1251 
1252         SmsDispatchersController smsDispatchersController =
1253                 satellitePhone.getSmsDispatchersController();
1254         if (smsDispatchersController == null) {
1255             ploge("sendErrorCodeAndCleanupPendingSms: smsDispatchersController is null.");
1256             pendingSmsMap.clear();
1257             return;
1258         }
1259 
1260         // Send error code to all the pending text
1261         for (Entry<Long, PendingRequest> entry : pendingSmsMap.entrySet()) {
1262             PendingRequest pendingRequest = entry.getValue();
1263             smsDispatchersController.onSendCarrierRoamingNbIotNtnTextError(
1264                     pendingRequest, errorCode);
1265             reportSendSmsCompleted(pendingRequest, errorCode);
1266         }
1267 
1268         // Clear pending text map
1269         pendingSmsMap.clear();
1270     }
1271 
handleEventSendSmsDone(int subId, long messageId, boolean success)1272     private void handleEventSendSmsDone(int subId, long messageId, boolean success) {
1273         synchronized (mLock) {
1274             PendingRequest pendingSms = mPendingSmsMap.remove(messageId);
1275             if (pendingSms == null) {
1276                 // Just return, the SMS is not sent by DatagramDispatcher such as Data SMS
1277                 plogd("handleEventSendSmsDone there is no pendingSms for messageId=" + messageId);
1278                 return;
1279             }
1280 
1281             mSendingInProgress = false;
1282             int datagramType = pendingSms.isMtSmsPolling
1283                     ? DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS  : DATAGRAM_TYPE_SMS;
1284 
1285             plogd("handleEventSendSmsDone subId=" + subId + " messageId=" + messageId
1286                     + " success=" + success + " datagramType=" + datagramType);
1287 
1288             if (success) {
1289                 // Update send status
1290                 mDatagramController.updateSendStatus(subId, datagramType,
1291                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS,
1292                         getPendingMessagesCount(), SATELLITE_RESULT_SUCCESS);
1293                 reportSendSmsCompleted(pendingSms, SATELLITE_RESULT_SUCCESS);
1294                 if (datagramType == DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS) {
1295                     startMtSmsPollingThrottle();
1296                     mShouldPollMtSms = false;
1297                 }
1298             } else {
1299                 // Update send status
1300                 mDatagramController.updateSendStatus(subId, datagramType,
1301                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
1302                         getPendingMessagesCount(), SATELLITE_RESULT_NETWORK_ERROR);
1303                 reportSendSmsCompleted(pendingSms, SATELLITE_RESULT_NETWORK_ERROR);
1304             }
1305 
1306             if (getPendingMessagesCount() > 0) {
1307                 sendPendingMessages();
1308             } else {
1309                 mDatagramController.updateSendStatus(subId, datagramType,
1310                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0,
1311                         SatelliteManager.SATELLITE_RESULT_SUCCESS);
1312             }
1313         }
1314     }
1315 
isEnabledMtSmsPolling()1316     private boolean isEnabledMtSmsPolling() {
1317         return mContext.getResources().getBoolean(R.bool.config_enabled_mt_sms_polling);
1318     }
1319 
getMtSmsPollingThrottleMillis()1320     private long getMtSmsPollingThrottleMillis() {
1321         return mContext.getResources().getInteger(
1322                 R.integer.config_mt_sms_polling_throttle_millis);
1323     }
1324 
shouldPollMtSms()1325     private boolean shouldPollMtSms() {
1326         SatelliteController satelliteController = SatelliteController.getInstance();
1327         Phone satellitePhone = satelliteController.getSatellitePhone();
1328         return isEnabledMtSmsPolling()
1329                 && satelliteController.shouldSendSmsToDatagramDispatcher(satellitePhone);
1330     }
1331 
handleCmdSendMtSmsPollingMessage()1332     private void handleCmdSendMtSmsPollingMessage() {
1333         synchronized (mLock) {
1334             if (!mShouldPollMtSms) {
1335                 plogd("sendMtSmsPollingMessage: mShouldPollMtSms=" + mShouldPollMtSms);
1336                 return;
1337             }
1338 
1339             plogd("sendMtSmsPollingMessage");
1340             if (!allowCheckMessageInNotConnected()) {
1341                 mShouldPollMtSms = false;
1342             }
1343 
1344             for (Entry<Long, PendingRequest> entry : mPendingSmsMap.entrySet()) {
1345                 PendingRequest pendingRequest = entry.getValue();
1346                 if (pendingRequest.isMtSmsPolling) {
1347                     plogd("sendMtSmsPollingMessage: mPendingSmsMap already "
1348                             + "has the polling message.");
1349                     return;
1350                 }
1351             }
1352         }
1353 
1354         Phone satellitePhone = SatelliteController.getInstance().getSatellitePhone();
1355         if (satellitePhone == null) {
1356             ploge("sendMtSmsPollingMessage: satellitePhone is null.");
1357             return;
1358         }
1359 
1360         SmsDispatchersController smsDispatchersController =
1361                 satellitePhone.getSmsDispatchersController();
1362         if (smsDispatchersController == null) {
1363             ploge("sendMtSmsPollingMessage: smsDispatchersController is null.");
1364             return;
1365         }
1366 
1367         smsDispatchersController.sendMtSmsPollingMessage();
1368     }
1369 
1370     @GuardedBy("mLock")
startMtSmsPollingThrottle()1371     private void startMtSmsPollingThrottle() {
1372         plogd("startMtSmsPollingThrottle");
1373         mIsMtSmsPollingThrottled = true;
1374         sendMessageDelayed(obtainMessage(EVENT_MT_SMS_POLLING_THROTTLE_TIMED_OUT),
1375                 getMtSmsPollingThrottleMillis());
1376     }
1377 
1378     @GuardedBy("mLock")
stopMtSmsPollingThrottle()1379     private void stopMtSmsPollingThrottle() {
1380         mIsMtSmsPollingThrottled = false;
1381         removeMessages(EVENT_MT_SMS_POLLING_THROTTLE_TIMED_OUT);
1382     }
1383 
allowMtSmsPolling()1384     private boolean allowMtSmsPolling() {
1385         SatelliteController satelliteController = SatelliteController.getInstance();
1386         int subId = satelliteController.getSelectedSatelliteSubId();
1387         boolean isP2PSmsDisallowed =
1388                 satelliteController.isP2PSmsDisallowedOnCarrierRoamingNtn(subId);
1389         if (isP2PSmsDisallowed) {
1390             plogd("allowMtSmsPolling: P2P SMS disallowed, subId = " + subId);
1391             return false;
1392         }
1393 
1394         boolean isModemStateConnectedOrTransferring;
1395         boolean isAligned;
1396         boolean isMtSmsPollingThrottled;
1397         synchronized (mLock) {
1398             isMtSmsPollingThrottled = mIsMtSmsPollingThrottled;
1399             isAligned = mIsAligned;
1400             isModemStateConnectedOrTransferring =
1401                     mModemState == SATELLITE_MODEM_STATE_CONNECTED
1402                             || mModemState == SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
1403         }
1404 
1405         if (isMtSmsPollingThrottled) {
1406             plogd("allowMtSmsPolling: polling is throttled");
1407             return false;
1408         }
1409 
1410         if (!isAligned) {
1411             plogd("allowMtSmsPolling: not aligned");
1412             return false;
1413         }
1414 
1415         if (!isModemStateConnectedOrTransferring && !allowCheckMessageInNotConnected()) {
1416             plogd("allowMtSmsPolling: not in service and "
1417                     + "allow_check_message_in_not_connected is disabled");
1418             return false;
1419         }
1420 
1421         plogd("allowMtSmsPolling: return true");
1422         return true;
1423     }
1424 
allowCheckMessageInNotConnected()1425     private boolean allowCheckMessageInNotConnected() {
1426         return mContext.getResources()
1427                 .getBoolean(R.bool.config_satellite_allow_check_message_in_not_connected);
1428     }
1429 
logd(@onNull String log)1430     private static void logd(@NonNull String log) {
1431         Log.d(TAG, log);
1432     }
1433 
loge(@onNull String log)1434     private static void loge(@NonNull String log) {
1435         Log.e(TAG, log);
1436     }
1437 
logw(@onNull String log)1438     private static void logw(@NonNull String log) { Log.w(TAG, log); }
1439 
plogd(@onNull String log)1440     private void plogd(@NonNull String log) {
1441         Log.d(TAG, log);
1442         if (mPersistentLogger != null) {
1443             mPersistentLogger.debug(TAG, log);
1444         }
1445     }
1446 
plogw(@onNull String log)1447     private void plogw(@NonNull String log) {
1448         Log.w(TAG, log);
1449         if (mPersistentLogger != null) {
1450             mPersistentLogger.warn(TAG, log);
1451         }
1452     }
1453 
ploge(@onNull String log)1454     private void ploge(@NonNull String log) {
1455         Log.e(TAG, log);
1456         if (mPersistentLogger != null) {
1457             mPersistentLogger.error(TAG, log);
1458         }
1459     }
1460 
updateSessionStatsWithPendingUserMsgCount(SatelliteSessionStats datagramStats)1461     public void updateSessionStatsWithPendingUserMsgCount(SatelliteSessionStats datagramStats) {
1462         synchronized (mLock) {
1463             Log.d("SessionMetricsStats1",
1464                     " mPendingEmergencyDatagramsMap size = "
1465                             + mPendingEmergencyDatagramsMap.size());
1466             Log.d("SessionMetricsStats1", " mPendingNonEmergencyDatagramsMap size = "
1467                     + mPendingNonEmergencyDatagramsMap.size());
1468             Log.d("SessionMetricsStats1", " mPendingSmsMap size = "
1469                     + mPendingSmsMap.size());
1470             for (Entry<Long, SendSatelliteDatagramArgument> entry :
1471                     mPendingEmergencyDatagramsMap.entrySet()) {
1472                 SendSatelliteDatagramArgument argument = entry.getValue();
1473                 Log.d("SessionMetricsStats1", "DataGramType1 =  "
1474                         + argument.datagramType);
1475                 datagramStats.updateCountOfUserMessagesInQueueToBeSent(argument.datagramType);
1476             }
1477             for (Entry<Long, SendSatelliteDatagramArgument> entry :
1478                     mPendingNonEmergencyDatagramsMap.entrySet()) {
1479                 SendSatelliteDatagramArgument argument = entry.getValue();
1480                 Log.d("SessionMetricsStats1", "DataGramType2 =  "
1481                         + argument.datagramType);
1482                 datagramStats.updateCountOfUserMessagesInQueueToBeSent(argument.datagramType);
1483             }
1484             for (Entry<Long, PendingRequest> entry : mPendingSmsMap.entrySet()) {
1485                 PendingRequest pendingRequest = entry.getValue();
1486                 int datagramType = pendingRequest.isMtSmsPolling
1487                         ? DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS : DATAGRAM_TYPE_SMS;
1488                 Log.d("SessionMetricsStats1", "DataGramType3 =  " + datagramType);
1489                 datagramStats.updateCountOfUserMessagesInQueueToBeSent(datagramType);
1490             }
1491         }
1492     }
1493 }
1494