• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.metrics;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.net.NetworkCapabilities;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.os.HandlerThread;
25 import android.telephony.AccessNetworkConstants;
26 import android.telephony.Annotation.NetworkType;
27 import android.telephony.CellSignalStrength;
28 import android.telephony.NetworkRegistrationInfo;
29 import android.telephony.ServiceState;
30 import android.telephony.TelephonyManager;
31 import android.telephony.data.DataCallResponse;
32 import android.telephony.data.DataCallResponse.LinkStatus;
33 
34 import com.android.internal.telephony.Phone;
35 import com.android.internal.telephony.PhoneFactory;
36 import com.android.internal.telephony.TelephonyStatsLog;
37 import com.android.internal.telephony.data.DataNetwork;
38 import com.android.internal.telephony.data.DataNetworkController;
39 import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
40 import com.android.internal.telephony.data.DataStallRecoveryManager;
41 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
42 import com.android.internal.telephony.subscription.SubscriptionManagerService;
43 import com.android.telephony.Rlog;
44 
45 import java.util.List;
46 
47 /**
48  * Generates metrics related to data stall recovery events per phone ID for the pushed atom.
49  */
50 public class DataStallRecoveryStats {
51 
52     /**
53      * Value indicating that link bandwidth is unspecified.
54      * Copied from {@code NetworkCapabilities#LINK_BANDWIDTH_UNSPECIFIED}
55      */
56     private static final int LINK_BANDWIDTH_UNSPECIFIED = 0;
57 
58     private static final String TAG = "DSRS-";
59 
60     // Handler to upload metrics.
61     private final @NonNull Handler mHandler;
62 
63     private final @NonNull String mTag;
64     private final @NonNull Phone mPhone;
65 
66     // The interface name of the internet network.
67     private @Nullable String mIfaceName = null;
68 
69     /* Metrics and stats data variables */
70     private int mPhoneId = 0;
71     private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
72     private int mSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
73     private int mBand = 0;
74     // The RAT used for data (including IWLAN).
75     private @NetworkType int mRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
76     private boolean mIsOpportunistic = false;
77     private boolean mIsMultiSim = false;
78     private int mNetworkRegState = NetworkRegistrationInfo
79                     .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
80     // Info of the other device in case of DSDS
81     private int mOtherSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
82     private int mOtherNetworkRegState = NetworkRegistrationInfo
83                     .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
84     // Link status of the data network
85     private @LinkStatus int mInternetLinkStatus = DataCallResponse.LINK_STATUS_UNKNOWN;
86 
87     // The link bandwidth of the data network
88     private int mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
89     private int mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
90 
91     /**
92      * Constructs a new instance of {@link DataStallRecoveryStats}.
93      */
DataStallRecoveryStats(@onNull final Phone phone, @NonNull final DataNetworkController dataNetworkController)94     public DataStallRecoveryStats(@NonNull final Phone phone,
95             @NonNull final DataNetworkController dataNetworkController) {
96         mTag = TAG + phone.getPhoneId();
97         mPhone = phone;
98 
99         HandlerThread handlerThread = new HandlerThread(mTag + "-thread");
100         handlerThread.start();
101         mHandler = new Handler(handlerThread.getLooper());
102 
103         dataNetworkController.registerDataNetworkControllerCallback(
104                 new DataNetworkControllerCallback(mHandler::post) {
105                 @Override
106                 public void onInternetDataNetworkConnected(
107                         @NonNull List<DataNetwork> internetNetworks) {
108                     for (DataNetwork dataNetwork : internetNetworks) {
109                         mIfaceName = dataNetwork.getLinkProperties().getInterfaceName();
110                         break;
111                     }
112                 }
113 
114                 @Override
115                 public void onInternetDataNetworkDisconnected() {
116                     mIfaceName = null;
117                 }
118 
119                 @Override
120                 public void onPhysicalLinkStatusChanged(@LinkStatus int status) {
121                     mInternetLinkStatus = status;
122                 }
123             });
124     }
125 
126     /**
127      * Create and push new atom when there is a data stall recovery event.
128      *
129      * @param action The recovery action.
130      * @param isRecovered Whether the data stall has been recovered.
131      * @param duration The duration from data stall occurred in milliseconds.
132      * @param reason The reason for the recovery.
133      * @param isFirstValidation Whether this is the first validation after recovery.
134      * @param durationOfAction The duration of the current action in milliseconds.
135      */
uploadMetrics( @ataStallRecoveryManager.RecoveryAction int action, boolean isRecovered, int duration, @DataStallRecoveryManager.RecoveredReason int reason, boolean isFirstValidation, int durationOfAction)136     public void uploadMetrics(
137             @DataStallRecoveryManager.RecoveryAction int action,
138             boolean isRecovered,
139             int duration,
140             @DataStallRecoveryManager.RecoveredReason int reason,
141             boolean isFirstValidation,
142             int durationOfAction) {
143 
144         mHandler.post(() -> {
145             // Update data stall stats
146             log("Set recovery action to " + action);
147 
148             // Refreshes the metrics data.
149             try {
150                 refreshMetricsData();
151             } catch (Exception e) {
152                 loge("The metrics data cannot be refreshed.", e);
153                 return;
154             }
155 
156             TelephonyStatsLog.write(
157                     TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED,
158                     mCarrierId,
159                     mRat,
160                     mSignalStrength,
161                     action,
162                     mIsOpportunistic,
163                     mIsMultiSim,
164                     mBand,
165                     isRecovered,
166                     duration,
167                     reason,
168                     mOtherSignalStrength,
169                     mOtherNetworkRegState,
170                     mNetworkRegState,
171                     isFirstValidation,
172                     mPhoneId,
173                     durationOfAction,
174                     mInternetLinkStatus,
175                     mLinkUpBandwidthKbps,
176                     mLinkDownBandwidthKbps);
177 
178             log("Upload stats: "
179                     + "Action:"
180                     + action
181                     + ", Recovered:"
182                     + isRecovered
183                     + ", Duration:"
184                     + duration
185                     + ", Reason:"
186                     + reason
187                     + ", First validation:"
188                     + isFirstValidation
189                     + ", Duration of action:"
190                     + durationOfAction
191                     + ", "
192                     + this);
193         });
194     }
195 
196     /**
197      * Refreshes the metrics data.
198      */
refreshMetricsData()199     private void refreshMetricsData() {
200         logd("Refreshes the metrics data.");
201         // Update phone id/carrier id and signal strength
202         mPhoneId = mPhone.getPhoneId() + 1;
203         mCarrierId = mPhone.getCarrierId();
204         mSignalStrength = mPhone.getSignalStrength().getLevel();
205 
206         // Update the bandwidth.
207         updateBandwidths();
208 
209         // Update the RAT and band.
210         updateRatAndBand();
211 
212         // Update the opportunistic state.
213         mIsOpportunistic = getIsOpportunistic(mPhone);
214 
215         // Update the multi-SIM state.
216         mIsMultiSim = SimSlotState.getCurrentState().numActiveSims > 1;
217 
218         // Update the network registration state.
219         updateNetworkRegState();
220 
221         // Update the DSDS information.
222         updateDsdsInfo();
223     }
224 
225     /**
226      * Updates the bandwidth for the current data network.
227      */
updateBandwidths()228     private void updateBandwidths() {
229         mLinkDownBandwidthKbps = mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
230 
231         if (mIfaceName == null) {
232             loge("Interface name is null");
233             return;
234         }
235 
236         DataNetworkController dataNetworkController = mPhone.getDataNetworkController();
237         if (dataNetworkController == null) {
238             loge("DataNetworkController is null");
239             return;
240         }
241 
242         DataNetwork dataNetwork = dataNetworkController.getDataNetworkByInterface(mIfaceName);
243         if (dataNetwork == null) {
244             loge("DataNetwork is null");
245             return;
246         }
247         NetworkCapabilities networkCapabilities = dataNetwork.getNetworkCapabilities();
248         if (networkCapabilities == null) {
249             loge("NetworkCapabilities is null");
250             return;
251         }
252 
253         mLinkDownBandwidthKbps = networkCapabilities.getLinkDownstreamBandwidthKbps();
254         mLinkUpBandwidthKbps = networkCapabilities.getLinkUpstreamBandwidthKbps();
255     }
256 
updateRatAndBand()257     private void updateRatAndBand() {
258         mRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
259         mBand = 0;
260         ServiceState serviceState = mPhone.getServiceState();
261         if (serviceState == null) {
262             loge("ServiceState is null");
263             return;
264         }
265 
266         mRat = serviceState.getDataNetworkType();
267         mBand =
268             (mRat == TelephonyManager.NETWORK_TYPE_IWLAN) ? 0 : ServiceStateStats.getBand(mPhone);
269     }
270 
getIsOpportunistic(@onNull Phone phone)271     private static boolean getIsOpportunistic(@NonNull Phone phone) {
272         SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance()
273                 .getSubscriptionInfoInternal(phone.getSubId());
274         return subInfo != null && subInfo.isOpportunistic();
275     }
276 
updateNetworkRegState()277     private void updateNetworkRegState() {
278         mNetworkRegState = NetworkRegistrationInfo
279             .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
280 
281         NetworkRegistrationInfo phoneRegInfo = mPhone.getServiceState()
282                 .getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
283                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
284         if (phoneRegInfo != null) {
285             mNetworkRegState = phoneRegInfo.getRegistrationState();
286         }
287     }
288 
updateDsdsInfo()289     private void updateDsdsInfo() {
290         mOtherSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
291         mOtherNetworkRegState = NetworkRegistrationInfo
292             .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
293         for (Phone otherPhone : PhoneFactory.getPhones()) {
294             if (otherPhone.getPhoneId() == mPhone.getPhoneId()) continue;
295             if (!getIsOpportunistic(otherPhone)) {
296                 mOtherSignalStrength = otherPhone.getSignalStrength().getLevel();
297                 NetworkRegistrationInfo regInfo = otherPhone.getServiceState()
298                         .getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
299                         AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
300                 if (regInfo != null) {
301                     mOtherNetworkRegState = regInfo.getRegistrationState();
302                 }
303                 break;
304             }
305         }
306     }
307 
308     /**
309      * Return bundled data stall recovery metrics data.
310      *
311      * @param action The recovery action.
312      * @param isRecovered Whether the data stall has been recovered.
313      * @param duration The duration from data stall occurred in milliseconds.
314      * @param reason The reason for the recovery.
315      * @param isFirstValidation Whether this is the first validation after recovery.
316      * @param durationOfAction The duration of the current action in milliseconds.
317      */
getDataStallRecoveryMetricsData( @ataStallRecoveryManager.RecoveryAction int action, boolean isRecovered, int duration, @DataStallRecoveryManager.RecoveredReason int reason, boolean isFirstValidation, int durationOfAction)318     public Bundle getDataStallRecoveryMetricsData(
319             @DataStallRecoveryManager.RecoveryAction int action,
320             boolean isRecovered,
321             int duration,
322             @DataStallRecoveryManager.RecoveredReason int reason,
323             boolean isFirstValidation,
324             int durationOfAction) {
325         Bundle bundle = new Bundle();
326         bundle.putInt("Action", action);
327         bundle.putBoolean("IsRecovered", isRecovered);
328         bundle.putInt("Duration", duration);
329         bundle.putInt("Reason", reason);
330         bundle.putBoolean("IsFirstValidation", isFirstValidation);
331         bundle.putInt("DurationOfAction", durationOfAction);
332         bundle.putInt("PhoneId", mPhoneId);
333         bundle.putInt("CarrierId", mCarrierId);
334         bundle.putInt("SignalStrength", mSignalStrength);
335         bundle.putInt("Band", mBand);
336         bundle.putInt("Rat", mRat);
337         bundle.putBoolean("IsOpportunistic", mIsOpportunistic);
338         bundle.putBoolean("IsMultiSim", mIsMultiSim);
339         bundle.putInt("NetworkRegState", mNetworkRegState);
340         bundle.putInt("OtherSignalStrength", mOtherSignalStrength);
341         bundle.putInt("OtherNetworkRegState", mOtherNetworkRegState);
342         bundle.putInt("InternetLinkStatus", mInternetLinkStatus);
343         bundle.putInt("LinkDownBandwidthKbps", mLinkDownBandwidthKbps);
344         bundle.putInt("LinkUpBandwidthKbps", mLinkUpBandwidthKbps);
345         return bundle;
346     }
347 
log(@onNull String s)348     private void log(@NonNull String s) {
349         Rlog.i(mTag, s);
350     }
351 
logd(@onNull String s)352     private void logd(@NonNull String s) {
353         Rlog.d(mTag, s);
354     }
355 
loge(@onNull String s)356     private void loge(@NonNull String s) {
357         Rlog.e(mTag, s);
358     }
359 
loge(@onNull String s, Throwable tr)360     private void loge(@NonNull String s, Throwable tr) {
361         Rlog.e(mTag, s, tr);
362     }
363 
364     @Override
toString()365     public String toString() {
366         return "DataStallRecoveryStats {"
367             + "Phone id:"
368             + mPhoneId
369             + ", Signal strength:"
370             + mSignalStrength
371             + ", Band:" + mBand
372             + ", RAT:" + mRat
373             + ", Opportunistic:"
374             + mIsOpportunistic
375             + ", Multi-SIM:"
376             + mIsMultiSim
377             + ", Network reg state:"
378             + mNetworkRegState
379             + ", Other signal strength:"
380             + mOtherSignalStrength
381             + ", Other network reg state:"
382             + mOtherNetworkRegState
383             + ", Link status:"
384             + mInternetLinkStatus
385             + ", Link down bandwidth:"
386             + mLinkDownBandwidthKbps
387             + ", Link up bandwidth:"
388             + mLinkUpBandwidthKbps
389             + "}";
390     }
391 }
392