• Home
  • History
  • Annotate
  • 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 static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
20  import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
21  import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT;
22  import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
23  import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
24  import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
25  
26  import android.annotation.ElapsedRealtimeLong;
27  import android.annotation.NonNull;
28  import android.annotation.Nullable;
29  import android.net.ConnectivityDiagnosticsManager;
30  import android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
31  import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
32  import android.net.ConnectivityDiagnosticsManager.DataStallReport;
33  import android.net.NetworkCapabilities;
34  import android.net.NetworkRequest;
35  import android.os.Bundle;
36  import android.os.Handler;
37  import android.os.HandlerThread;
38  import android.os.PersistableBundle;
39  import android.os.SystemClock;
40  import android.telephony.AccessNetworkConstants;
41  import android.telephony.Annotation.NetworkType;
42  import android.telephony.CellSignalStrength;
43  import android.telephony.NetworkRegistrationInfo;
44  import android.telephony.ServiceState;
45  import android.telephony.TelephonyManager;
46  import android.telephony.data.DataCallResponse;
47  import android.telephony.data.DataCallResponse.LinkStatus;
48  import android.text.TextUtils;
49  
50  import com.android.internal.telephony.Phone;
51  import com.android.internal.telephony.PhoneFactory;
52  import com.android.internal.telephony.TelephonyStatsLog;
53  import com.android.internal.telephony.data.DataNetwork;
54  import com.android.internal.telephony.data.DataNetworkController;
55  import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
56  import com.android.internal.telephony.data.DataStallRecoveryManager;
57  import com.android.internal.telephony.flags.FeatureFlags;
58  import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
59  import com.android.internal.telephony.subscription.SubscriptionManagerService;
60  import com.android.telephony.Rlog;
61  
62  import java.util.Set;
63  import java.util.concurrent.Executor;
64  import java.util.concurrent.TimeUnit;
65  
66  /**
67   * Generates metrics related to data stall recovery events per phone ID for the pushed atom.
68   */
69  public class DataStallRecoveryStats {
70  
71      /**
72       * Value indicating that link bandwidth is unspecified.
73       * Copied from {@code NetworkCapabilities#LINK_BANDWIDTH_UNSPECIFIED}
74       */
75      private static final int LINK_BANDWIDTH_UNSPECIFIED = 0;
76  
77      private static final String TAG = "DSRS-";
78  
79      private static final int UNSET_DIAGNOSTIC_STATE = -1;
80  
81      private static final long REFRESH_DURATION_IN_MILLIS = TimeUnit.MINUTES.toMillis(3);
82  
83      // Handler to upload metrics.
84      private final @NonNull Handler mHandler;
85  
86      private final @NonNull String mTag;
87      private final @NonNull Phone mPhone;
88      private final @NonNull TelephonyManager mTelephonyManager;
89      private final @NonNull FeatureFlags mFeatureFlags;
90  
91      // Flag to control the DSRS diagnostics
92      private final boolean mIsDsrsDiagnosticsEnabled;
93  
94      // The interface name of the internet network.
95      private @Nullable String mIfaceName = null;
96  
97      /* Metrics and stats data variables */
98      // Record metrics refresh time in milliseconds to decide whether to refresh data again
99      @ElapsedRealtimeLong
100      private long mMetricsReflashTime = 0L;
101      private int mPhoneId = 0;
102      private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
103      private int mConvertedMccMnc = -1;
104      private int mSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
105      private int mBand = 0;
106      // The RAT used for data (including IWLAN).
107      private @NetworkType int mRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
108      private boolean mIsOpportunistic = false;
109      private boolean mIsMultiSim = false;
110      private int mNetworkRegState = NetworkRegistrationInfo
111                      .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
112      // Info of the other device in case of DSDS
113      private int mOtherSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
114      private int mOtherNetworkRegState = NetworkRegistrationInfo
115                      .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
116      // Link status of the data network
117      private @LinkStatus int mInternetLinkStatus = DataCallResponse.LINK_STATUS_UNKNOWN;
118  
119      // The link bandwidth of the data network
120      private int mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
121      private int mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
122  
123      // Connectivity diagnostics states
124      private int mNetworkProbesResult = UNSET_DIAGNOSTIC_STATE;
125      private int mNetworkProbesType = UNSET_DIAGNOSTIC_STATE;
126      private int mNetworkValidationResult = UNSET_DIAGNOSTIC_STATE;
127      private int mTcpMetricsCollectionPeriodMillis = UNSET_DIAGNOSTIC_STATE;
128      private int mTcpPacketFailRate = UNSET_DIAGNOSTIC_STATE;
129      private int mDnsConsecutiveTimeouts = UNSET_DIAGNOSTIC_STATE;
130  
131      private ConnectivityDiagnosticsManager mConnectivityDiagnosticsManager = null;
132      private ConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback = null;
133      private static final Executor INLINE_EXECUTOR = x -> x.run();
134  
135      /**
136       * Constructs a new instance of {@link DataStallRecoveryStats}.
137       */
DataStallRecoveryStats( @onNull final Phone phone, @NonNull FeatureFlags featureFlags, @NonNull final DataNetworkController dataNetworkController)138      public DataStallRecoveryStats(
139              @NonNull final Phone phone,
140              @NonNull FeatureFlags featureFlags,
141              @NonNull final DataNetworkController dataNetworkController) {
142          mTag = TAG + phone.getPhoneId();
143          mPhone = phone;
144          mFeatureFlags = featureFlags;
145  
146          HandlerThread handlerThread = new HandlerThread(mTag + "-thread");
147          handlerThread.start();
148          mHandler = new Handler(handlerThread.getLooper());
149          mTelephonyManager = mPhone.getContext().getSystemService(TelephonyManager.class);
150  
151          dataNetworkController.registerDataNetworkControllerCallback(
152                  new DataNetworkControllerCallback(mHandler::post) {
153                  @Override
154                  public void onConnectedInternetDataNetworksChanged(
155                          @NonNull Set<DataNetwork> internetNetworks) {
156                      mIfaceName = null;
157                      for (DataNetwork dataNetwork : internetNetworks) {
158                          mIfaceName = dataNetwork.getLinkProperties().getInterfaceName();
159                          break;
160                      }
161                  }
162  
163                  @Override
164                  public void onPhysicalLinkStatusChanged(@LinkStatus int status) {
165                      mInternetLinkStatus = status;
166                  }
167              });
168  
169          mIsDsrsDiagnosticsEnabled = mFeatureFlags.dsrsDiagnosticsEnabled();
170          if (mIsDsrsDiagnosticsEnabled) {
171              try {
172                  // Register ConnectivityDiagnosticsCallback to get diagnostics states
173                  mConnectivityDiagnosticsManager =
174                      mPhone.getContext().getSystemService(ConnectivityDiagnosticsManager.class);
175                  mConnectivityDiagnosticsCallback = new ConnectivityDiagnosticsCallback() {
176                      @Override
177                      public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {
178                          PersistableBundle bundle = report.getAdditionalInfo();
179                          mNetworkProbesResult = bundle.getInt(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK);
180                          mNetworkProbesType = bundle.getInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK);
181                          mNetworkValidationResult = bundle.getInt(KEY_NETWORK_VALIDATION_RESULT);
182                      }
183  
184                      @Override
185                      public void onDataStallSuspected(@NonNull DataStallReport report) {
186                          PersistableBundle bundle = report.getStallDetails();
187                          mTcpMetricsCollectionPeriodMillis =
188                              bundle.getInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS);
189                          mTcpPacketFailRate = bundle.getInt(KEY_TCP_PACKET_FAIL_RATE);
190                          mDnsConsecutiveTimeouts = bundle.getInt(KEY_DNS_CONSECUTIVE_TIMEOUTS);
191                      }
192                  };
193                  mConnectivityDiagnosticsManager.registerConnectivityDiagnosticsCallback(
194                      new NetworkRequest.Builder()
195                          .clearCapabilities()
196                          .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
197                          .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
198                          .build(),
199                          INLINE_EXECUTOR,
200                          mConnectivityDiagnosticsCallback
201                  );
202              } catch (Exception e) {
203                  mConnectivityDiagnosticsManager = null;
204                  mConnectivityDiagnosticsCallback = null;
205              }
206          }
207      }
208  
209      /**
210       * Create and push new atom when there is a data stall recovery event.
211       *
212       * @param action The recovery action.
213       * @param isRecovered Whether the data stall has been recovered.
214       * @param duration The duration from data stall occurred in milliseconds.
215       * @param reason The reason for the recovery.
216       * @param isFirstValidation Whether this is the first validation after recovery.
217       * @param durationOfAction The duration of the current action in milliseconds.
218       */
uploadMetrics( @ataStallRecoveryManager.RecoveryAction int action, boolean isRecovered, int duration, @DataStallRecoveryManager.RecoveredReason int reason, boolean isFirstValidation, int durationOfAction)219      public void uploadMetrics(
220              @DataStallRecoveryManager.RecoveryAction int action,
221              boolean isRecovered,
222              int duration,
223              @DataStallRecoveryManager.RecoveredReason int reason,
224              boolean isFirstValidation,
225              int durationOfAction) {
226  
227          mHandler.post(() -> {
228              // Update data stall stats
229              log("Set recovery action to " + action);
230  
231              // Refreshes the metrics data.
232              try {
233                  refreshMetricsData();
234              } catch (Exception e) {
235                  loge("The metrics data cannot be refreshed.", e);
236                  return;
237              }
238  
239              TelephonyStatsLog.write(
240                      TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED,
241                      mCarrierId,
242                      mRat,
243                      mSignalStrength,
244                      action,
245                      mIsOpportunistic,
246                      mIsMultiSim,
247                      mBand,
248                      isRecovered,
249                      duration,
250                      reason,
251                      mOtherSignalStrength,
252                      mOtherNetworkRegState,
253                      mNetworkRegState,
254                      isFirstValidation,
255                      mPhoneId,
256                      durationOfAction,
257                      mInternetLinkStatus,
258                      mLinkUpBandwidthKbps,
259                      mLinkDownBandwidthKbps);
260  
261              log("Upload stats: "
262                      + "Action:"
263                      + action
264                      + ", Recovered:"
265                      + isRecovered
266                      + ", Duration:"
267                      + duration
268                      + ", Reason:"
269                      + reason
270                      + ", First validation:"
271                      + isFirstValidation
272                      + ", Duration of action:"
273                      + durationOfAction
274                      + ", "
275                      + this);
276          });
277      }
278  
279      /**
280       * Refreshes the metrics data.
281       */
refreshMetricsData()282      private void refreshMetricsData() {
283          logd("Refreshes the metrics data.");
284          // Update the metrics reflash time
285          mMetricsReflashTime = SystemClock.elapsedRealtime();
286          // Update phone id/carrier id and signal strength
287          mPhoneId = mPhone.getPhoneId() + 1;
288          mCarrierId = mPhone.getCarrierId();
289          mSignalStrength = mPhone.getSignalStrength().getLevel();
290          if (mIsDsrsDiagnosticsEnabled) {
291              // Get the MCCMNC and convert it to an int
292              String networkOperator = mTelephonyManager.getNetworkOperator();
293              if (!TextUtils.isEmpty(networkOperator)) {
294                  try {
295                      mConvertedMccMnc = Integer.parseInt(networkOperator);
296                  } catch (NumberFormatException e) {
297                      loge("Invalid MCCMNC format: " + networkOperator);
298                      mConvertedMccMnc = -1;
299                  }
300              } else {
301                  mConvertedMccMnc = -1;
302              }
303          }
304  
305          // Update the bandwidth.
306          updateBandwidths();
307  
308          // Update the RAT and band.
309          updateRatAndBand();
310  
311          // Update the opportunistic state.
312          mIsOpportunistic = getIsOpportunistic(mPhone);
313  
314          // Update the multi-SIM state.
315          mIsMultiSim = SimSlotState.getCurrentState().numActiveSims > 1;
316  
317          // Update the network registration state.
318          updateNetworkRegState();
319  
320          // Update the DSDS information.
321          updateDsdsInfo();
322      }
323  
324      /**
325       * Updates the bandwidth for the current data network.
326       */
updateBandwidths()327      private void updateBandwidths() {
328          mLinkDownBandwidthKbps = mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
329  
330          if (mIfaceName == null) {
331              loge("Interface name is null");
332              return;
333          }
334  
335          DataNetworkController dataNetworkController = mPhone.getDataNetworkController();
336          if (dataNetworkController == null) {
337              loge("DataNetworkController is null");
338              return;
339          }
340  
341          DataNetwork dataNetwork = dataNetworkController.getDataNetworkByInterface(mIfaceName);
342          if (dataNetwork == null) {
343              loge("DataNetwork is null");
344              return;
345          }
346          NetworkCapabilities networkCapabilities = dataNetwork.getNetworkCapabilities();
347          if (networkCapabilities == null) {
348              loge("NetworkCapabilities is null");
349              return;
350          }
351  
352          mLinkDownBandwidthKbps = networkCapabilities.getLinkDownstreamBandwidthKbps();
353          mLinkUpBandwidthKbps = networkCapabilities.getLinkUpstreamBandwidthKbps();
354      }
355  
updateRatAndBand()356      private void updateRatAndBand() {
357          mRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
358          mBand = 0;
359          ServiceState serviceState = mPhone.getServiceState();
360          if (serviceState == null) {
361              loge("ServiceState is null");
362              return;
363          }
364  
365          mRat = serviceState.getDataNetworkType();
366          mBand =
367              (mRat == TelephonyManager.NETWORK_TYPE_IWLAN) ? 0 : ServiceStateStats.getBand(mPhone);
368      }
369  
getIsOpportunistic(@onNull Phone phone)370      private static boolean getIsOpportunistic(@NonNull Phone phone) {
371          SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance()
372                  .getSubscriptionInfoInternal(phone.getSubId());
373          return subInfo != null && subInfo.isOpportunistic();
374      }
375  
updateNetworkRegState()376      private void updateNetworkRegState() {
377          mNetworkRegState = NetworkRegistrationInfo
378              .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
379  
380          NetworkRegistrationInfo phoneRegInfo = mPhone.getServiceState()
381                  .getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
382                  AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
383          if (phoneRegInfo != null) {
384              mNetworkRegState = phoneRegInfo.getRegistrationState();
385          }
386      }
387  
updateDsdsInfo()388      private void updateDsdsInfo() {
389          mOtherSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
390          mOtherNetworkRegState = NetworkRegistrationInfo
391              .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
392          for (Phone otherPhone : PhoneFactory.getPhones()) {
393              if (otherPhone.getPhoneId() == mPhone.getPhoneId()) continue;
394              if (!getIsOpportunistic(otherPhone)) {
395                  mOtherSignalStrength = otherPhone.getSignalStrength().getLevel();
396                  NetworkRegistrationInfo regInfo = otherPhone.getServiceState()
397                          .getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
398                          AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
399                  if (regInfo != null) {
400                      mOtherNetworkRegState = regInfo.getRegistrationState();
401                  }
402                  break;
403              }
404          }
405      }
406  
407      /**
408       * Return bundled data stall recovery metrics data.
409       *
410       * @param action The recovery action.
411       * @param isRecovered Whether the data stall has been recovered.
412       * @param duration The duration from data stall occurred in milliseconds.
413       * @param reason The reason for the recovery.
414       * @param validationCount The total number of validation duration a data stall.
415       * @param actionValidationCount The number of validation for current action during a data stall
416       * @param durationOfAction The duration of the current action in milliseconds.
417       */
getDataStallRecoveryMetricsData( @ataStallRecoveryManager.RecoveryAction int action, boolean isRecovered, int duration, @DataStallRecoveryManager.RecoveredReason int reason, int validationCount, int actionValidationCount, int durationOfAction)418      public Bundle getDataStallRecoveryMetricsData(
419              @DataStallRecoveryManager.RecoveryAction int action,
420              boolean isRecovered,
421              int duration,
422              @DataStallRecoveryManager.RecoveredReason int reason,
423              int validationCount,
424              int actionValidationCount,
425              int durationOfAction) {
426  
427          if (mIsDsrsDiagnosticsEnabled) {
428              // Refresh data if the data has not been updated within 3 minutes
429              final long refreshDuration = SystemClock.elapsedRealtime() - mMetricsReflashTime;
430              if (refreshDuration > REFRESH_DURATION_IN_MILLIS) {
431                  // Refreshes the metrics data.
432                  try {
433                      refreshMetricsData();
434                  } catch (Exception e) {
435                      loge("The metrics data cannot be refreshed.", e);
436                  }
437              }
438          }
439  
440          Bundle bundle = new Bundle();
441  
442          if (mIsDsrsDiagnosticsEnabled) {
443              bundle.putInt("Action", action);
444              bundle.putInt("IsRecovered", isRecovered ? 1 : 0);
445              bundle.putInt("Duration", duration);
446              bundle.putInt("Reason", reason);
447              bundle.putInt("DurationOfAction", durationOfAction);
448              bundle.putInt("ValidationCount", validationCount);
449              bundle.putInt("ActionValidationCount", actionValidationCount);
450              bundle.putInt("PhoneId", mPhoneId);
451              bundle.putInt("CarrierId", mCarrierId);
452              bundle.putInt("MccMnc", mConvertedMccMnc);
453              bundle.putInt("SignalStrength", mSignalStrength);
454              bundle.putInt("Band", mBand);
455              bundle.putInt("Rat", mRat);
456              bundle.putInt("IsOpportunistic", mIsOpportunistic ? 1 : 0);
457              bundle.putInt("IsMultiSim", mIsMultiSim ? 1 : 0);
458              bundle.putInt("NetworkRegState", mNetworkRegState);
459              bundle.putInt("OtherSignalStrength", mOtherSignalStrength);
460              bundle.putInt("OtherNetworkRegState", mOtherNetworkRegState);
461              bundle.putInt("InternetLinkStatus", mInternetLinkStatus);
462              bundle.putInt("LinkDownBandwidthKbps", mLinkDownBandwidthKbps);
463              bundle.putInt("LinkUpBandwidthKbps", mLinkUpBandwidthKbps);
464              bundle.putInt("NetworkProbesResult", mNetworkProbesResult);
465              bundle.putInt("NetworkProbesType", mNetworkProbesType);
466              bundle.putInt("NetworkValidationResult", mNetworkValidationResult);
467              bundle.putInt("TcpMetricsCollectionPeriodMillis", mTcpMetricsCollectionPeriodMillis);
468              bundle.putInt("TcpPacketFailRate", mTcpPacketFailRate);
469              bundle.putInt("DnsConsecutiveTimeouts", mDnsConsecutiveTimeouts);
470          } else {
471              bundle.putInt("Action", action);
472              bundle.putBoolean("IsRecovered", isRecovered);
473              bundle.putInt("Duration", duration);
474              bundle.putInt("Reason", reason);
475              bundle.putBoolean("IsFirstValidation", validationCount == 1);
476              bundle.putInt("DurationOfAction", durationOfAction);
477              bundle.putInt("PhoneId", mPhoneId);
478              bundle.putInt("CarrierId", mCarrierId);
479              bundle.putInt("SignalStrength", mSignalStrength);
480              bundle.putInt("Band", mBand);
481              bundle.putInt("Rat", mRat);
482              bundle.putBoolean("IsOpportunistic", mIsOpportunistic);
483              bundle.putBoolean("IsMultiSim", mIsMultiSim);
484              bundle.putInt("NetworkRegState", mNetworkRegState);
485              bundle.putInt("OtherSignalStrength", mOtherSignalStrength);
486              bundle.putInt("OtherNetworkRegState", mOtherNetworkRegState);
487              bundle.putInt("InternetLinkStatus", mInternetLinkStatus);
488              bundle.putInt("LinkDownBandwidthKbps", mLinkDownBandwidthKbps);
489              bundle.putInt("LinkUpBandwidthKbps", mLinkUpBandwidthKbps);
490          }
491  
492          return bundle;
493      }
494  
log(@onNull String s)495      private void log(@NonNull String s) {
496          Rlog.i(mTag, s);
497      }
498  
logd(@onNull String s)499      private void logd(@NonNull String s) {
500          Rlog.d(mTag, s);
501      }
502  
loge(@onNull String s)503      private void loge(@NonNull String s) {
504          Rlog.e(mTag, s);
505      }
506  
loge(@onNull String s, Throwable tr)507      private void loge(@NonNull String s, Throwable tr) {
508          Rlog.e(mTag, s, tr);
509      }
510  
511      @Override
toString()512      public String toString() {
513          return "DataStallRecoveryStats {"
514              + "Phone id:"
515              + mPhoneId
516              + ", Signal strength:"
517              + mSignalStrength
518              + ", Band:" + mBand
519              + ", RAT:" + mRat
520              + ", Opportunistic:"
521              + mIsOpportunistic
522              + ", Multi-SIM:"
523              + mIsMultiSim
524              + ", Network reg state:"
525              + mNetworkRegState
526              + ", Other signal strength:"
527              + mOtherSignalStrength
528              + ", Other network reg state:"
529              + mOtherNetworkRegState
530              + ", Link status:"
531              + mInternetLinkStatus
532              + ", Link down bandwidth:"
533              + mLinkDownBandwidthKbps
534              + ", Link up bandwidth:"
535              + mLinkUpBandwidthKbps
536              + "}";
537      }
538  }
539