1 /* 2 * Copyright (C) 2022 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.networkstack.tethering.metrics; 18 19 import static android.app.usage.NetworkStats.Bucket.STATE_ALL; 20 import static android.app.usage.NetworkStats.Bucket.TAG_NONE; 21 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; 22 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 23 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; 24 import static android.net.NetworkCapabilities.TRANSPORT_LOWPAN; 25 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 26 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; 27 import static android.net.NetworkStats.DEFAULT_NETWORK_YES; 28 import static android.net.NetworkStats.METERED_YES; 29 import static android.net.NetworkStats.UID_TETHERING; 30 import static android.net.NetworkTemplate.MATCH_BLUETOOTH; 31 import static android.net.NetworkTemplate.MATCH_ETHERNET; 32 import static android.net.NetworkTemplate.MATCH_MOBILE; 33 import static android.net.NetworkTemplate.MATCH_WIFI; 34 import static android.net.TetheringManager.TETHERING_BLUETOOTH; 35 import static android.net.TetheringManager.TETHERING_ETHERNET; 36 import static android.net.TetheringManager.TETHERING_NCM; 37 import static android.net.TetheringManager.TETHERING_USB; 38 import static android.net.TetheringManager.TETHERING_WIFI; 39 import static android.net.TetheringManager.TETHERING_WIFI_P2P; 40 import static android.net.TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; 41 import static android.net.TetheringManager.TETHER_ERROR_DISABLE_FORWARDING_ERROR; 42 import static android.net.TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR; 43 import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; 44 import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; 45 import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR; 46 import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION; 47 import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; 48 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; 49 import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; 50 import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; 51 import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; 52 import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE; 53 import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; 54 import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED; 55 import static android.net.TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; 56 57 import android.annotation.Nullable; 58 import android.app.usage.NetworkStats; 59 import android.app.usage.NetworkStatsManager; 60 import android.content.Context; 61 import android.net.NetworkCapabilities; 62 import android.net.NetworkTemplate; 63 import android.os.Handler; 64 import android.os.HandlerThread; 65 import android.stats.connectivity.DownstreamType; 66 import android.stats.connectivity.ErrorCode; 67 import android.stats.connectivity.UpstreamType; 68 import android.stats.connectivity.UserType; 69 import android.util.ArrayMap; 70 import android.util.Log; 71 import android.util.SparseArray; 72 73 import androidx.annotation.NonNull; 74 import androidx.annotation.VisibleForTesting; 75 76 import com.android.modules.utils.build.SdkLevel; 77 import com.android.net.module.util.DeviceConfigUtils; 78 import com.android.net.module.util.HandlerUtils; 79 import com.android.networkstack.tethering.UpstreamNetworkState; 80 81 import java.util.ArrayList; 82 import java.util.Arrays; 83 84 /** 85 * Collection of utilities for tethering metrics. 86 * 87 * <p>This class is thread-safe. All accesses to this class will be either posting to the internal 88 * handler thread for processing or checking whether the access is from the internal handler 89 * thread. However, the constructor is an exception, as it is called on another thread. 90 * 91 * To see if the logs are properly sent to statsd, execute following commands 92 * 93 * $ adb shell cmd stats print-logs 94 * $ adb logcat | grep statsd OR $ adb logcat -b stats 95 * 96 * @hide 97 */ 98 public class TetheringMetrics { 99 private static final String TAG = TetheringMetrics.class.getSimpleName(); 100 private static final boolean DBG = false; 101 private static final String SETTINGS_PKG_NAME = "com.android.settings"; 102 private static final String SYSTEMUI_PKG_NAME = "com.android.systemui"; 103 private static final String GMS_PKG_NAME = "com.google.android.gms"; 104 /** 105 * A feature flag to control whether upstream data usage metrics should be enabled. 106 */ 107 private static final String TETHER_UPSTREAM_DATA_USAGE_METRICS = 108 "tether_upstream_data_usage_metrics"; 109 @VisibleForTesting 110 static final DataUsage EMPTY = new DataUsage(0L /* txBytes */, 0L /* rxBytes */); 111 private final SparseArray<NetworkTetheringReported.Builder> mBuilderMap = new SparseArray<>(); 112 private final SparseArray<Long> mDownstreamStartTime = new SparseArray<Long>(); 113 private final ArrayList<RecordUpstreamEvent> mUpstreamEventList = new ArrayList<>(); 114 // Store the last reported data usage for each upstream type to be used for calculating the 115 // usage delta. The keys are the upstream types, and the values are the tethering UID data 116 // usage for the corresponding types. Retrieve the baseline data usage when tethering is 117 // enabled, update it when the upstream changes, and clear it when tethering is disabled. 118 private final ArrayMap<UpstreamType, DataUsage> mLastReportedUpstreamUsage = new ArrayMap<>(); 119 private final Context mContext; 120 private final Dependencies mDependencies; 121 private final NetworkStatsManager mNetworkStatsManager; 122 private final Handler mHandler; 123 private UpstreamType mCurrentUpstream = null; 124 private Long mCurrentUpStreamStartTime = 0L; 125 126 /** 127 * Dependencies of TetheringMetrics, for injection in tests. 128 */ 129 @VisibleForTesting 130 public static class Dependencies { 131 /** 132 * @see TetheringStatsLog 133 */ write(NetworkTetheringReported reported)134 public void write(NetworkTetheringReported reported) { 135 TetheringStatsLog.write( 136 TetheringStatsLog.NETWORK_TETHERING_REPORTED, 137 reported.getErrorCode().getNumber(), 138 reported.getDownstreamType().getNumber(), 139 reported.getUpstreamType().getNumber(), 140 reported.getUserType().getNumber(), 141 reported.getUpstreamEvents().toByteArray(), 142 reported.getDurationMillis()); 143 } 144 145 /** 146 * @see System#currentTimeMillis() 147 */ timeNow()148 public long timeNow() { 149 return System.currentTimeMillis(); 150 } 151 152 /** 153 * Indicates whether {@link #TETHER_UPSTREAM_DATA_USAGE_METRICS} is enabled. 154 */ isUpstreamDataUsageMetricsEnabled(Context context)155 public boolean isUpstreamDataUsageMetricsEnabled(Context context) { 156 // Getting data usage requires building a NetworkTemplate. However, the 157 // NetworkTemplate#Builder API was introduced in Android T. 158 return SdkLevel.isAtLeastT() && DeviceConfigUtils.isTetheringFeatureNotChickenedOut( 159 context, TETHER_UPSTREAM_DATA_USAGE_METRICS); 160 } 161 162 /** 163 * @see Handler 164 * 165 * Note: This should only be called once, within the constructor, as it creates a new 166 * thread. Calling it multiple times could lead to a thread leak. 167 */ 168 @NonNull createHandler()169 public Handler createHandler() { 170 final HandlerThread thread = new HandlerThread(TAG); 171 thread.start(); 172 return new Handler(thread.getLooper()); 173 } 174 } 175 176 /** 177 * Constructor for the TetheringMetrics class. 178 * 179 * @param context The Context object used to access system services. 180 */ TetheringMetrics(Context context)181 public TetheringMetrics(Context context) { 182 this(context, new Dependencies()); 183 } 184 TetheringMetrics(Context context, Dependencies dependencies)185 TetheringMetrics(Context context, Dependencies dependencies) { 186 mContext = context; 187 mDependencies = dependencies; 188 mNetworkStatsManager = mContext.getSystemService(NetworkStatsManager.class); 189 mHandler = dependencies.createHandler(); 190 } 191 192 @VisibleForTesting 193 static class DataUsage { 194 public final long txBytes; 195 public final long rxBytes; 196 DataUsage(long txBytes, long rxBytes)197 DataUsage(long txBytes, long rxBytes) { 198 this.txBytes = txBytes; 199 this.rxBytes = rxBytes; 200 } 201 202 /*** Calculate the data usage delta from give new and old usage */ subtract(DataUsage newUsage, DataUsage oldUsage)203 public static DataUsage subtract(DataUsage newUsage, DataUsage oldUsage) { 204 return new DataUsage( 205 newUsage.txBytes - oldUsage.txBytes, 206 newUsage.rxBytes - oldUsage.rxBytes); 207 } 208 209 @Override hashCode()210 public int hashCode() { 211 return (int) (txBytes & 0xFFFFFFFF) 212 + ((int) (txBytes >> 32) * 3) 213 + ((int) (rxBytes & 0xFFFFFFFF) * 5) 214 + ((int) (rxBytes >> 32) * 7); 215 } 216 217 @Override equals(Object other)218 public boolean equals(Object other) { 219 if (this == other) { 220 return true; 221 } 222 if (!(other instanceof DataUsage)) { 223 return false; 224 } 225 return txBytes == ((DataUsage) other).txBytes 226 && rxBytes == ((DataUsage) other).rxBytes; 227 } 228 229 } 230 231 private static class RecordUpstreamEvent { 232 final long mStartTime; 233 final long mStopTime; 234 final UpstreamType mUpstreamType; 235 final DataUsage mDataUsage; 236 RecordUpstreamEvent(final long startTime, final long stopTime, final UpstreamType upstream, final DataUsage dataUsage)237 RecordUpstreamEvent(final long startTime, final long stopTime, 238 final UpstreamType upstream, final DataUsage dataUsage) { 239 mStartTime = startTime; 240 mStopTime = stopTime; 241 mUpstreamType = upstream; 242 mDataUsage = dataUsage; 243 } 244 } 245 246 /** 247 * Creates a |NetworkTetheringReported.Builder| object to update the tethering stats for the 248 * specified downstream type and caller's package name. Initializes the upstream events, error 249 * code, and duration to default values. Sets the start time for the downstream type in the 250 * |mDownstreamStartTime| map. 251 * @param downstreamType The type of downstream connection (e.g. Wifi, USB, Bluetooth). 252 * @param callerPkg The package name of the caller. 253 */ createBuilder(final int downstreamType, final String callerPkg)254 public void createBuilder(final int downstreamType, final String callerPkg) { 255 mHandler.post(() -> handleCreateBuilder(downstreamType, callerPkg)); 256 } 257 handleCreateBuilder(final int downstreamType, final String callerPkg)258 private void handleCreateBuilder(final int downstreamType, final String callerPkg) { 259 NetworkTetheringReported.Builder statsBuilder = NetworkTetheringReported.newBuilder() 260 .setDownstreamType(downstreamTypeToEnum(downstreamType)) 261 .setUserType(userTypeToEnum(callerPkg)) 262 .setUpstreamType(UpstreamType.UT_UNKNOWN) 263 .setErrorCode(ErrorCode.EC_NO_ERROR) 264 .setUpstreamEvents(UpstreamEvents.newBuilder()) 265 .setDurationMillis(0); 266 mBuilderMap.put(downstreamType, statsBuilder); 267 mDownstreamStartTime.put(downstreamType, mDependencies.timeNow()); 268 } 269 270 /** 271 * Update the error code of the given downstream type in the Tethering stats. 272 * @param downstreamType The downstream type whose error code to update. 273 * @param errCode The error code to set. 274 */ updateErrorCode(final int downstreamType, final int errCode)275 public void updateErrorCode(final int downstreamType, final int errCode) { 276 mHandler.post(() -> handleUpdateErrorCode(downstreamType, errCode)); 277 } 278 handleUpdateErrorCode(final int downstreamType, final int errCode)279 private void handleUpdateErrorCode(final int downstreamType, final int errCode) { 280 NetworkTetheringReported.Builder statsBuilder = mBuilderMap.get(downstreamType); 281 if (statsBuilder == null) { 282 Log.e(TAG, "Given downstreamType does not exist, this is a bug!"); 283 return; 284 } 285 statsBuilder.setErrorCode(errorCodeToEnum(errCode)); 286 } 287 288 /** 289 * Calculates the data usage difference between the current and previous usage for the 290 * specified upstream type. 291 * 292 * Note: This must be called before updating mCurrentUpstream when changing the upstream. 293 * 294 * @return A DataUsage object containing the calculated difference in transmitted (tx) and 295 * received (rx) bytes. 296 */ calculateDataUsageDelta(@ullable UpstreamType upstream)297 private DataUsage calculateDataUsageDelta(@Nullable UpstreamType upstream) { 298 if (!mDependencies.isUpstreamDataUsageMetricsEnabled(mContext)) { 299 return EMPTY; 300 } 301 302 if (upstream == null || !isUsageSupportedForUpstreamType(upstream)) { 303 return EMPTY; 304 } 305 306 final DataUsage oldUsage = mLastReportedUpstreamUsage.getOrDefault(upstream, EMPTY); 307 if (oldUsage.equals(EMPTY)) { 308 Log.d(TAG, "No usage baseline for the upstream=" + upstream); 309 return EMPTY; 310 } 311 // TODO(b/370724247): Fix data usage which might be incorrect if the device uses 312 // tethering with the same upstream for over 15 days. 313 // Need to refresh the baseline usage data. If the network switches back to Wi-Fi after 314 // using cellular data (Wi-Fi -> Cellular -> Wi-Fi), the old baseline might be 315 // inaccurate, leading to incorrect delta calculations. 316 final DataUsage newUsage = getCurrentDataUsageForUpstreamType(upstream); 317 mLastReportedUpstreamUsage.put(upstream, newUsage); 318 return DataUsage.subtract(newUsage, oldUsage); 319 } 320 321 /** 322 * Update the list of upstream types and their duration whenever the current upstream type 323 * changes. 324 * @param ns The UpstreamNetworkState object representing the current upstream network state. 325 */ maybeUpdateUpstreamType(@ullable final UpstreamNetworkState ns)326 public void maybeUpdateUpstreamType(@Nullable final UpstreamNetworkState ns) { 327 mHandler.post(() -> handleMaybeUpdateUpstreamType(ns)); 328 } 329 handleMaybeUpdateUpstreamType(@ullable final UpstreamNetworkState ns)330 private void handleMaybeUpdateUpstreamType(@Nullable final UpstreamNetworkState ns) { 331 UpstreamType upstream = transportTypeToUpstreamTypeEnum(ns); 332 if (upstream.equals(mCurrentUpstream)) return; 333 334 final long newTime = mDependencies.timeNow(); 335 if (mCurrentUpstream != null) { 336 final DataUsage dataUsage = calculateDataUsageDelta(mCurrentUpstream); 337 mUpstreamEventList.add(new RecordUpstreamEvent(mCurrentUpStreamStartTime, newTime, 338 mCurrentUpstream, dataUsage)); 339 } 340 mCurrentUpstream = upstream; 341 mCurrentUpStreamStartTime = newTime; 342 } 343 344 /** 345 * Updates the upstream events builder with a new upstream event. 346 * @param upstreamEventsBuilder the builder for the upstream events list 347 * @param start the start time of the upstream event 348 * @param stop the stop time of the upstream event 349 * @param upstream the type of upstream type (e.g. Wifi, Cellular, Bluetooth, ...) 350 */ addUpstreamEvent(final UpstreamEvents.Builder upstreamEventsBuilder, final long start, final long stop, @Nullable final UpstreamType upstream, final long txBytes, final long rxBytes)351 private void addUpstreamEvent(final UpstreamEvents.Builder upstreamEventsBuilder, 352 final long start, final long stop, @Nullable final UpstreamType upstream, 353 final long txBytes, final long rxBytes) { 354 final UpstreamEvent.Builder upstreamEventBuilder = UpstreamEvent.newBuilder() 355 .setUpstreamType(upstream == null ? UpstreamType.UT_NO_NETWORK : upstream) 356 .setDurationMillis(stop - start) 357 .setTxBytes(txBytes) 358 .setRxBytes(rxBytes); 359 upstreamEventsBuilder.addUpstreamEvent(upstreamEventBuilder); 360 } 361 362 /** 363 * Updates the |NetworkTetheringReported.Builder| with relevant upstream events associated with 364 * the downstream event identified by the given downstream start time. 365 * 366 * This method iterates through the list of upstream events and adds any relevant events to a 367 * |UpstreamEvents.Builder|. Upstream events are considered relevant if their stop time is 368 * greater than or equal to the given downstream start time. The method also adds the last 369 * upstream event that occurred up until the current time. 370 * 371 * The resulting |UpstreamEvents.Builder| is then added to the 372 * |NetworkTetheringReported.Builder|, along with the duration of the downstream event 373 * (i.e., stop time minus downstream start time). 374 * 375 * @param statsBuilder the builder for the NetworkTetheringReported message 376 * @param downstreamStartTime the start time of the downstream event to find relevant upstream 377 * events for 378 */ noteDownstreamStopped(final NetworkTetheringReported.Builder statsBuilder, final long downstreamStartTime)379 private void noteDownstreamStopped(final NetworkTetheringReported.Builder statsBuilder, 380 final long downstreamStartTime) { 381 UpstreamEvents.Builder upstreamEventsBuilder = UpstreamEvents.newBuilder(); 382 383 for (RecordUpstreamEvent event : mUpstreamEventList) { 384 if (downstreamStartTime > event.mStopTime) continue; 385 386 final long startTime = Math.max(downstreamStartTime, event.mStartTime); 387 // Handle completed upstream events. 388 addUpstreamEvent(upstreamEventsBuilder, startTime, event.mStopTime, 389 event.mUpstreamType, event.mDataUsage.txBytes, event.mDataUsage.rxBytes); 390 } 391 final long startTime = Math.max(downstreamStartTime, mCurrentUpStreamStartTime); 392 final long stopTime = mDependencies.timeNow(); 393 // Handle the last upstream event. 394 final DataUsage dataUsage = calculateDataUsageDelta(mCurrentUpstream); 395 addUpstreamEvent(upstreamEventsBuilder, startTime, stopTime, mCurrentUpstream, 396 dataUsage.txBytes, dataUsage.rxBytes); 397 statsBuilder.setUpstreamEvents(upstreamEventsBuilder); 398 statsBuilder.setDurationMillis(stopTime - downstreamStartTime); 399 } 400 401 /** 402 * Removes tethering statistics for the given downstream type. If there are any stats to write 403 * for the downstream event associated with the type, they are written before removing the 404 * statistics. 405 * 406 * If the given downstream type does not exist in the map, an error message is logged and the 407 * method returns without doing anything. 408 * 409 * @param downstreamType the type of downstream event to remove statistics for 410 */ sendReport(final int downstreamType)411 public void sendReport(final int downstreamType) { 412 mHandler.post(() -> handleSendReport(downstreamType)); 413 } 414 handleSendReport(final int downstreamType)415 private void handleSendReport(final int downstreamType) { 416 final NetworkTetheringReported.Builder statsBuilder = mBuilderMap.get(downstreamType); 417 if (statsBuilder == null) { 418 Log.e(TAG, "Given downstreamType does not exist, this is a bug!"); 419 return; 420 } 421 422 noteDownstreamStopped(statsBuilder, mDownstreamStartTime.get(downstreamType)); 423 write(statsBuilder.build()); 424 425 mBuilderMap.remove(downstreamType); 426 mDownstreamStartTime.remove(downstreamType); 427 } 428 429 /** 430 * Collects tethering statistics and writes them to the statsd pipeline. This method takes in a 431 * NetworkTetheringReported object, extracts its fields and uses them to write statistics data 432 * to the statsd pipeline. 433 * 434 * @param reported a NetworkTetheringReported object containing statistics to write 435 */ write(@onNull final NetworkTetheringReported reported)436 private void write(@NonNull final NetworkTetheringReported reported) { 437 mDependencies.write(reported); 438 if (DBG) { 439 Log.d( 440 TAG, 441 "Write errorCode: " 442 + reported.getErrorCode().getNumber() 443 + ", downstreamType: " 444 + reported.getDownstreamType().getNumber() 445 + ", upstreamType: " 446 + reported.getUpstreamType().getNumber() 447 + ", userType: " 448 + reported.getUserType().getNumber() 449 + ", upstreamTypes: " 450 + Arrays.toString(reported.getUpstreamEvents().toByteArray()) 451 + ", durationMillis: " 452 + reported.getDurationMillis()); 453 } 454 } 455 456 /** 457 * Initialize the upstream data usage baseline when tethering is turned on. 458 */ initUpstreamUsageBaseline()459 public void initUpstreamUsageBaseline() { 460 mHandler.post(() -> handleInitUpstreamUsageBaseline()); 461 } 462 handleInitUpstreamUsageBaseline()463 private void handleInitUpstreamUsageBaseline() { 464 if (!mDependencies.isUpstreamDataUsageMetricsEnabled(mContext)) { 465 return; 466 } 467 468 if (!mLastReportedUpstreamUsage.isEmpty()) { 469 Log.wtf(TAG, "The upstream usage baseline has been initialed."); 470 return; 471 } 472 473 for (UpstreamType type : UpstreamType.values()) { 474 if (!isUsageSupportedForUpstreamType(type)) continue; 475 mLastReportedUpstreamUsage.put(type, getCurrentDataUsageForUpstreamType(type)); 476 } 477 } 478 479 @VisibleForTesting 480 @NonNull getLastReportedUsageFromUpstreamType(@onNull UpstreamType type)481 DataUsage getLastReportedUsageFromUpstreamType(@NonNull UpstreamType type) { 482 HandlerUtils.ensureRunningOnHandlerThread(mHandler); 483 return mLastReportedUpstreamUsage.getOrDefault(type, EMPTY); 484 } 485 486 487 /** 488 * Get the current usage for given upstream type. 489 */ 490 @NonNull getCurrentDataUsageForUpstreamType(@onNull UpstreamType type)491 private DataUsage getCurrentDataUsageForUpstreamType(@NonNull UpstreamType type) { 492 final NetworkStats stats = mNetworkStatsManager.queryDetailsForUidTagState( 493 buildNetworkTemplateForUpstreamType(type), Long.MIN_VALUE, Long.MAX_VALUE, 494 UID_TETHERING, TAG_NONE, STATE_ALL); 495 496 final NetworkStats.Bucket bucket = new NetworkStats.Bucket(); 497 Long totalTxBytes = 0L; 498 Long totalRxBytes = 0L; 499 while (stats.hasNextBucket()) { 500 stats.getNextBucket(bucket); 501 totalTxBytes += bucket.getTxBytes(); 502 totalRxBytes += bucket.getRxBytes(); 503 } 504 return new DataUsage(totalTxBytes, totalRxBytes); 505 } 506 507 /** 508 * Cleans up the variables related to upstream events when tethering is turned off. 509 */ cleanup()510 public void cleanup() { 511 mHandler.post(() -> handleCleanup()); 512 } 513 handleCleanup()514 private void handleCleanup() { 515 mUpstreamEventList.clear(); 516 mCurrentUpstream = null; 517 mCurrentUpStreamStartTime = 0L; 518 mLastReportedUpstreamUsage.clear(); 519 } 520 downstreamTypeToEnum(final int ifaceType)521 private DownstreamType downstreamTypeToEnum(final int ifaceType) { 522 switch(ifaceType) { 523 case TETHERING_WIFI: 524 return DownstreamType.DS_TETHERING_WIFI; 525 case TETHERING_WIFI_P2P: 526 return DownstreamType.DS_TETHERING_WIFI_P2P; 527 case TETHERING_USB: 528 return DownstreamType.DS_TETHERING_USB; 529 case TETHERING_BLUETOOTH: 530 return DownstreamType.DS_TETHERING_BLUETOOTH; 531 case TETHERING_NCM: 532 return DownstreamType.DS_TETHERING_NCM; 533 case TETHERING_ETHERNET: 534 return DownstreamType.DS_TETHERING_ETHERNET; 535 default: 536 return DownstreamType.DS_UNSPECIFIED; 537 } 538 } 539 errorCodeToEnum(final int lastError)540 private ErrorCode errorCodeToEnum(final int lastError) { 541 switch(lastError) { 542 case TETHER_ERROR_NO_ERROR: 543 return ErrorCode.EC_NO_ERROR; 544 case TETHER_ERROR_UNKNOWN_IFACE: 545 return ErrorCode.EC_UNKNOWN_IFACE; 546 case TETHER_ERROR_SERVICE_UNAVAIL: 547 return ErrorCode.EC_SERVICE_UNAVAIL; 548 case TETHER_ERROR_UNSUPPORTED: 549 return ErrorCode.EC_UNSUPPORTED; 550 case TETHER_ERROR_UNAVAIL_IFACE: 551 return ErrorCode.EC_UNAVAIL_IFACE; 552 case TETHER_ERROR_INTERNAL_ERROR: 553 return ErrorCode.EC_INTERNAL_ERROR; 554 case TETHER_ERROR_TETHER_IFACE_ERROR: 555 return ErrorCode.EC_TETHER_IFACE_ERROR; 556 case TETHER_ERROR_UNTETHER_IFACE_ERROR: 557 return ErrorCode.EC_UNTETHER_IFACE_ERROR; 558 case TETHER_ERROR_ENABLE_FORWARDING_ERROR: 559 return ErrorCode.EC_ENABLE_FORWARDING_ERROR; 560 case TETHER_ERROR_DISABLE_FORWARDING_ERROR: 561 return ErrorCode.EC_DISABLE_FORWARDING_ERROR; 562 case TETHER_ERROR_IFACE_CFG_ERROR: 563 return ErrorCode.EC_IFACE_CFG_ERROR; 564 case TETHER_ERROR_PROVISIONING_FAILED: 565 return ErrorCode.EC_PROVISIONING_FAILED; 566 case TETHER_ERROR_DHCPSERVER_ERROR: 567 return ErrorCode.EC_DHCPSERVER_ERROR; 568 case TETHER_ERROR_ENTITLEMENT_UNKNOWN: 569 return ErrorCode.EC_ENTITLEMENT_UNKNOWN; 570 case TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION: 571 return ErrorCode.EC_NO_CHANGE_TETHERING_PERMISSION; 572 case TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION: 573 return ErrorCode.EC_NO_ACCESS_TETHERING_PERMISSION; 574 default: 575 return ErrorCode.EC_UNKNOWN_TYPE; 576 } 577 } 578 userTypeToEnum(final String callerPkg)579 private UserType userTypeToEnum(final String callerPkg) { 580 if (callerPkg.equals(SETTINGS_PKG_NAME)) { 581 return UserType.USER_SETTINGS; 582 } else if (callerPkg.equals(SYSTEMUI_PKG_NAME)) { 583 return UserType.USER_SYSTEMUI; 584 } else if (callerPkg.equals(GMS_PKG_NAME)) { 585 return UserType.USER_GMS; 586 } else { 587 return UserType.USER_UNKNOWN; 588 } 589 } 590 transportTypeToUpstreamTypeEnum(final UpstreamNetworkState ns)591 private UpstreamType transportTypeToUpstreamTypeEnum(final UpstreamNetworkState ns) { 592 final NetworkCapabilities nc = (ns != null) ? ns.networkCapabilities : null; 593 if (nc == null) return UpstreamType.UT_NO_NETWORK; 594 595 final int typeCount = nc.getTransportTypes().length; 596 // It's possible for a VCN network to be mapped to UT_UNKNOWN, as it may consist of both 597 // Wi-Fi and cellular transport. 598 // TODO: It's necessary to define a new upstream type for VCN, which can be identified by 599 // NET_CAPABILITY_NOT_VCN_MANAGED. 600 if (typeCount > 1) return UpstreamType.UT_UNKNOWN; 601 602 if (nc.hasTransport(TRANSPORT_CELLULAR)) return UpstreamType.UT_CELLULAR; 603 if (nc.hasTransport(TRANSPORT_WIFI)) return UpstreamType.UT_WIFI; 604 if (nc.hasTransport(TRANSPORT_BLUETOOTH)) return UpstreamType.UT_BLUETOOTH; 605 if (nc.hasTransport(TRANSPORT_ETHERNET)) return UpstreamType.UT_ETHERNET; 606 if (nc.hasTransport(TRANSPORT_WIFI_AWARE)) return UpstreamType.UT_WIFI_AWARE; 607 if (nc.hasTransport(TRANSPORT_LOWPAN)) return UpstreamType.UT_LOWPAN; 608 609 return UpstreamType.UT_UNKNOWN; 610 } 611 612 /** 613 * Check whether tethering metrics' data usage can be collected for a given upstream type. 614 * 615 * @param type the upstream type 616 */ isUsageSupportedForUpstreamType(@onNull UpstreamType type)617 public static boolean isUsageSupportedForUpstreamType(@NonNull UpstreamType type) { 618 switch(type) { 619 case UT_CELLULAR: 620 case UT_WIFI: 621 case UT_BLUETOOTH: 622 case UT_ETHERNET: 623 return true; 624 default: 625 break; 626 } 627 return false; 628 } 629 630 /** 631 * Build NetworkTemplate for the given upstream type. 632 * 633 * <p> NetworkTemplate.Builder API was introduced in Android T. 634 * 635 * @param type the upstream type 636 * @return A NetworkTemplate object with a corresponding match rule or null if tethering 637 * metrics' data usage cannot be collected for a given upstream type. 638 */ 639 @Nullable buildNetworkTemplateForUpstreamType(@onNull UpstreamType type)640 public static NetworkTemplate buildNetworkTemplateForUpstreamType(@NonNull UpstreamType type) { 641 if (!isUsageSupportedForUpstreamType(type)) return null; 642 643 switch (type) { 644 case UT_CELLULAR: 645 // TODO: Handle the DUN connection, which is not a default network. 646 return new NetworkTemplate.Builder(MATCH_MOBILE) 647 .setMeteredness(METERED_YES) 648 .setDefaultNetworkStatus(DEFAULT_NETWORK_YES) 649 .build(); 650 case UT_WIFI: 651 return new NetworkTemplate.Builder(MATCH_WIFI) 652 .setMeteredness(METERED_YES) 653 .setDefaultNetworkStatus(DEFAULT_NETWORK_YES) 654 .build(); 655 case UT_BLUETOOTH: 656 return new NetworkTemplate.Builder(MATCH_BLUETOOTH) 657 .setMeteredness(METERED_YES) 658 .setDefaultNetworkStatus(DEFAULT_NETWORK_YES) 659 .build(); 660 case UT_ETHERNET: 661 return new NetworkTemplate.Builder(MATCH_ETHERNET) 662 .setMeteredness(METERED_YES) 663 .setDefaultNetworkStatus(DEFAULT_NETWORK_YES) 664 .build(); 665 default: 666 Log.e(TAG, "Unsupported UpstreamType: " + type.name()); 667 break; 668 } 669 return null; 670 } 671 } 672