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.metrics;
18 
19 import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE;
20 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
21 
22 import android.annotation.NonNull;
23 import android.os.Bundle;
24 import android.os.ResultReceiver;
25 import android.telephony.satellite.NtnSignalStrength;
26 import android.telephony.satellite.SatelliteManager;
27 import android.telephony.satellite.SatelliteSessionStats;
28 import android.util.Log;
29 
30 import com.android.internal.telephony.metrics.SatelliteStats;
31 import com.android.internal.telephony.satellite.DatagramDispatcher;
32 
33 /**
34  * Stats to log to satellite session metrics
35  */
36 public class SessionMetricsStats {
37     private static final String TAG = SessionMetricsStats.class.getSimpleName();
38     private static final boolean DBG = false;
39 
40     private static SessionMetricsStats sInstance = null;
41     private @SatelliteManager.SatelliteResult int mInitializationResult;
42     private @SatelliteManager.NTRadioTechnology int mRadioTechnology;
43     private @SatelliteManager.SatelliteResult int mTerminationResult;
44     private long mInitializationProcessingTimeMillis;
45     private long mTerminationProcessingTimeMillis;
46     private int mSessionDurationSec;
47     private int mCountOfSuccessfulOutgoingDatagram;
48     private int mCountOfFailedOutgoingDatagram;
49     private int mCountOfTimedOutUserMessagesWaitingForConnection;
50     private int mCountOfTimedOutUserMessagesWaitingForAck;
51     private int mCountOfSuccessfulIncomingDatagram;
52     private int mCountOfIncomingDatagramFailed;
53     private boolean mIsDemoMode;
54     private @NtnSignalStrength.NtnSignalStrengthLevel int mMaxNtnSignalStrengthLevel;
55 
SessionMetricsStats()56     private SessionMetricsStats() {
57         initializeSessionMetricsParam();
58     }
59 
60     /**
61      * Returns the Singleton instance of SessionMetricsStats class.
62      * If an instance of the Singleton class has not been created,
63      * it creates a new instance and returns it. Otherwise, it returns
64      * the existing instance.
65      * @return the Singleton instance of SessionMetricsStats.
66      */
getInstance()67     public static SessionMetricsStats getInstance() {
68         if (sInstance == null) {
69             loge("create new SessionMetricsStats.");
70             sInstance = new SessionMetricsStats();
71         }
72         return sInstance;
73     }
74 
75     /** Sets the satellite initialization result. */
setInitializationResult( @atelliteManager.SatelliteResult int result)76     public SessionMetricsStats setInitializationResult(
77             @SatelliteManager.SatelliteResult int result) {
78         logd("setInitializationResult(" + result + ")");
79         mInitializationResult = result;
80         return this;
81     }
82 
83     /** Sets the satellite ratio technology. */
setSatelliteTechnology( @atelliteManager.NTRadioTechnology int radioTechnology)84     public SessionMetricsStats setSatelliteTechnology(
85             @SatelliteManager.NTRadioTechnology int radioTechnology) {
86         logd("setSatelliteTechnology(" + radioTechnology + ")");
87         mRadioTechnology = radioTechnology;
88         return this;
89     }
90 
91     /** Sets the satellite de-initialization result. */
setTerminationResult( @atelliteManager.SatelliteResult int result)92     public SessionMetricsStats setTerminationResult(
93             @SatelliteManager.SatelliteResult int result) {
94         logd("setTerminationResult(" + result + ")");
95         mTerminationResult = result;
96         return this;
97     }
98 
99     /** Sets the satellite initialization processing time. */
setInitializationProcessingTime(long processingTime)100     public SessionMetricsStats setInitializationProcessingTime(long processingTime) {
101         logd("setInitializationProcessingTime(" + processingTime + ")");
102         mInitializationProcessingTimeMillis = processingTime;
103         return this;
104     }
105 
106     /** Sets the satellite de-initialization processing time. */
setTerminationProcessingTime(long processingTime)107     public SessionMetricsStats setTerminationProcessingTime(long processingTime) {
108         logd("setTerminationProcessingTime(" + processingTime + ")");
109         mTerminationProcessingTimeMillis = processingTime;
110         return this;
111     }
112 
113     /** Sets the total enabled time for the satellite session. */
setSessionDurationSec(int sessionDurationSec)114     public SessionMetricsStats setSessionDurationSec(int sessionDurationSec) {
115         logd("setSessionDuration(" + sessionDurationSec + ")");
116         mSessionDurationSec = sessionDurationSec;
117         return this;
118     }
119 
120     /** Increase the count of successful outgoing datagram transmission. */
addCountOfSuccessfulOutgoingDatagram( @onNull @atelliteManager.DatagramType int datagramType)121     public SessionMetricsStats addCountOfSuccessfulOutgoingDatagram(
122             @NonNull @SatelliteManager.DatagramType int datagramType) {
123         if (datagramType == SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE) {
124             // Ignore KEEP_ALIVE messages
125             return this;
126         }
127 
128         mCountOfSuccessfulOutgoingDatagram++;
129         logd("addCountOfSuccessfulOutgoingDatagram: current count="
130                 + mCountOfSuccessfulOutgoingDatagram);
131         return this;
132     }
133 
134     /** Increase the count of failed outgoing datagram transmission. */
addCountOfFailedOutgoingDatagram( @onNull @atelliteManager.DatagramType int datagramType, @NonNull @SatelliteManager.SatelliteResult int resultCode)135     public SessionMetricsStats addCountOfFailedOutgoingDatagram(
136             @NonNull @SatelliteManager.DatagramType int datagramType,
137             @NonNull @SatelliteManager.SatelliteResult int resultCode) {
138         if (datagramType == SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE) {
139             // Ignore KEEP_ALIVE messages
140             return this;
141         }
142 
143         mCountOfFailedOutgoingDatagram++;
144         logd("addCountOfFailedOutgoingDatagram: current count=" + mCountOfFailedOutgoingDatagram);
145 
146         if (resultCode == SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE) {
147             addCountOfTimedOutUserMessagesWaitingForConnection(datagramType);
148         } else if (resultCode == SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT) {
149             addCountOfTimedOutUserMessagesWaitingForAck(datagramType);
150         }
151 
152         return this;
153     }
154 
155     /** Increase the count of user messages that timed out waiting for connection. */
addCountOfTimedOutUserMessagesWaitingForConnection( @onNull @atelliteManager.DatagramType int datagramType)156     private SessionMetricsStats addCountOfTimedOutUserMessagesWaitingForConnection(
157             @NonNull @SatelliteManager.DatagramType int datagramType) {
158         if (datagramType == SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE) {
159             // Ignore KEEP_ALIVE messages
160             return this;
161         }
162 
163         mCountOfTimedOutUserMessagesWaitingForConnection++;
164         logd("addCountOfTimedOutUserMessagesWaitingForConnection: current count="
165                 + mCountOfTimedOutUserMessagesWaitingForConnection);
166         return this;
167     }
168 
169     /** Increase the count of user messages that timed out waiting for ack. */
addCountOfTimedOutUserMessagesWaitingForAck( @onNull @atelliteManager.DatagramType int datagramType)170     private SessionMetricsStats addCountOfTimedOutUserMessagesWaitingForAck(
171             @NonNull @SatelliteManager.DatagramType int datagramType) {
172         if (datagramType == SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE) {
173             // Ignore KEEP_ALIVE messages
174             return this;
175         }
176 
177         mCountOfTimedOutUserMessagesWaitingForAck++;
178         logd("addCountOfTimedOutUserMessagesWaitingForAck: current count="
179                 + mCountOfTimedOutUserMessagesWaitingForAck);
180         return this;
181     }
182 
183     /** Increase the count of successful incoming datagram transmission. */
addCountOfSuccessfulIncomingDatagram()184     public SessionMetricsStats addCountOfSuccessfulIncomingDatagram() {
185         mCountOfSuccessfulIncomingDatagram++;
186         logd("addCountOfSuccessfulIncomingDatagram: current count="
187                 + mCountOfSuccessfulIncomingDatagram);
188         return this;
189     }
190 
191     /** Increase the count of failed incoming datagram transmission. */
addCountOfFailedIncomingDatagram()192     public SessionMetricsStats addCountOfFailedIncomingDatagram() {
193         mCountOfIncomingDatagramFailed++;
194         logd("addCountOfFailedIncomingDatagram: current count=" + mCountOfIncomingDatagramFailed);
195         return this;
196     }
197 
198     /** Sets whether the session is enabled for demo mode or not. */
setIsDemoMode(boolean isDemoMode)199     public SessionMetricsStats setIsDemoMode(boolean isDemoMode) {
200         mIsDemoMode = isDemoMode;
201         logd("setIsDemoMode(" + mIsDemoMode + ")");
202         return this;
203     }
204 
205     /** Updates the max Ntn signal strength level for the session. */
updateMaxNtnSignalStrengthLevel( @tnSignalStrength.NtnSignalStrengthLevel int latestNtnSignalStrengthLevel)206     public SessionMetricsStats updateMaxNtnSignalStrengthLevel(
207             @NtnSignalStrength.NtnSignalStrengthLevel int latestNtnSignalStrengthLevel) {
208         if (latestNtnSignalStrengthLevel > mMaxNtnSignalStrengthLevel) {
209             mMaxNtnSignalStrengthLevel = latestNtnSignalStrengthLevel;
210         }
211         logd("updateMaxNtnSignalsStrength: latest signal strength=" + latestNtnSignalStrengthLevel
212                 + ", max signal strength=" + mMaxNtnSignalStrengthLevel);
213         return this;
214     }
215 
216     /** Report the session metrics atoms to PersistAtomsStorage in telephony. */
reportSessionMetrics()217     public void reportSessionMetrics() {
218         SatelliteStats.SatelliteSessionParams sessionParams =
219                 new SatelliteStats.SatelliteSessionParams.Builder()
220                         .setSatelliteServiceInitializationResult(mInitializationResult)
221                         .setSatelliteTechnology(mRadioTechnology)
222                         .setTerminationResult(mTerminationResult)
223                         .setInitializationProcessingTime(mInitializationProcessingTimeMillis)
224                         .setTerminationProcessingTime(mTerminationProcessingTimeMillis)
225                         .setSessionDuration(mSessionDurationSec)
226                         .setCountOfOutgoingDatagramSuccess(mCountOfSuccessfulOutgoingDatagram)
227                         .setCountOfOutgoingDatagramFailed(mCountOfFailedOutgoingDatagram)
228                         .setCountOfIncomingDatagramSuccess(mCountOfSuccessfulIncomingDatagram)
229                         .setCountOfIncomingDatagramFailed(mCountOfIncomingDatagramFailed)
230                         .setIsDemoMode(mIsDemoMode)
231                         .setMaxNtnSignalStrengthLevel(mMaxNtnSignalStrengthLevel)
232                         .build();
233         logd("reportSessionMetrics: " + sessionParams.toString());
234         SatelliteStats.getInstance().onSatelliteSessionMetrics(sessionParams);
235         initializeSessionMetricsParam();
236     }
237 
238     /** Returns {@link SatelliteSessionStats} of the satellite service. */
requestSatelliteSessionStats(int subId, @NonNull ResultReceiver result)239     public void requestSatelliteSessionStats(int subId, @NonNull ResultReceiver result) {
240         Bundle bundle = new Bundle();
241         SatelliteSessionStats sessionStats = new SatelliteSessionStats.Builder()
242                 .setCountOfSuccessfulUserMessages(mCountOfSuccessfulOutgoingDatagram)
243                 .setCountOfUnsuccessfulUserMessages(mCountOfFailedOutgoingDatagram)
244                 .setCountOfTimedOutUserMessagesWaitingForConnection(
245                         mCountOfTimedOutUserMessagesWaitingForConnection)
246                 .setCountOfTimedOutUserMessagesWaitingForAck(
247                         mCountOfTimedOutUserMessagesWaitingForAck)
248                 .setCountOfUserMessagesInQueueToBeSent(
249                         DatagramDispatcher.getInstance().getPendingUserMessagesCount())
250                 .build();
251         bundle.putParcelable(SatelliteManager.KEY_SESSION_STATS, sessionStats);
252         result.send(SATELLITE_RESULT_SUCCESS, bundle);
253     }
254 
255     /** Returns the processing time for satellite session initialization. */
getSessionInitializationProcessingTimeMillis()256     public long getSessionInitializationProcessingTimeMillis() {
257         return mInitializationProcessingTimeMillis;
258     }
259 
260     /** Returns the processing time for satellite session termination. */
getSessionTerminationProcessingTimeMillis()261     public long getSessionTerminationProcessingTimeMillis() {
262         return mTerminationProcessingTimeMillis;
263     }
264 
initializeSessionMetricsParam()265     private void initializeSessionMetricsParam() {
266         mInitializationResult = SatelliteManager.SATELLITE_RESULT_SUCCESS;
267         mRadioTechnology = SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN;
268         mTerminationResult = SatelliteManager.SATELLITE_RESULT_SUCCESS;
269         mInitializationProcessingTimeMillis = 0;
270         mTerminationProcessingTimeMillis = 0;
271         mSessionDurationSec = 0;
272         mCountOfSuccessfulOutgoingDatagram = 0;
273         mCountOfFailedOutgoingDatagram = 0;
274         mCountOfTimedOutUserMessagesWaitingForConnection = 0;
275         mCountOfTimedOutUserMessagesWaitingForAck = 0;
276         mCountOfSuccessfulIncomingDatagram = 0;
277         mCountOfIncomingDatagramFailed = 0;
278         mIsDemoMode = false;
279         mMaxNtnSignalStrengthLevel = NTN_SIGNAL_STRENGTH_NONE;
280     }
281 
logd(@onNull String log)282     private static void logd(@NonNull String log) {
283         if (DBG) {
284             Log.d(TAG, log);
285         }
286     }
287 
loge(@onNull String log)288     private static void loge(@NonNull String log) {
289         Log.e(TAG, log);
290     }
291 }
292