1 /* 2 * Copyright (C) 2018 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; 18 19 import static android.content.pm.PackageManager.GET_ACTIVITIES; 20 import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; 21 import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; 22 import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; 23 import static android.net.TetheringConstants.EXTRA_TETHER_PROVISIONING_RESPONSE; 24 import static android.net.TetheringConstants.EXTRA_TETHER_SILENT_PROVISIONING_ACTION; 25 import static android.net.TetheringConstants.EXTRA_TETHER_SUBID; 26 import static android.net.TetheringConstants.EXTRA_TETHER_UI_PROVISIONING_APP_NAME; 27 import static android.net.TetheringManager.TETHERING_BLUETOOTH; 28 import static android.net.TetheringManager.TETHERING_ETHERNET; 29 import static android.net.TetheringManager.TETHERING_INVALID; 30 import static android.net.TetheringManager.TETHERING_USB; 31 import static android.net.TetheringManager.TETHERING_WIFI; 32 import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; 33 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; 34 import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; 35 36 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; 37 import static com.android.networkstack.apishim.ConstantsShim.ACTION_TETHER_UNSUPPORTED_CARRIER_UI; 38 import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_NOT_EXPORTED; 39 40 import android.annotation.NonNull; 41 import android.app.ActivityManager; 42 import android.app.AlarmManager; 43 import android.app.PendingIntent; 44 import android.content.BroadcastReceiver; 45 import android.content.ComponentName; 46 import android.content.Context; 47 import android.content.Intent; 48 import android.content.IntentFilter; 49 import android.content.pm.PackageManager; 50 import android.os.Bundle; 51 import android.os.Handler; 52 import android.os.Parcel; 53 import android.os.ResultReceiver; 54 import android.os.SystemClock; 55 import android.os.SystemProperties; 56 import android.os.UserHandle; 57 import android.os.UserManager; 58 import android.provider.Settings; 59 import android.util.SparseIntArray; 60 61 import androidx.annotation.Nullable; 62 63 import com.android.internal.annotations.VisibleForTesting; 64 import com.android.modules.utils.build.SdkLevel; 65 import com.android.net.module.util.FrameworkConnectivityStatsLog; 66 import com.android.net.module.util.SharedLog; 67 68 import java.io.PrintWriter; 69 import java.util.BitSet; 70 71 /** 72 * Re-check tethering provisioning for enabled downstream tether types. 73 * Reference TetheringManager.TETHERING_{@code *} for each tether type. 74 * 75 * All methods of this class must be accessed from the thread of tethering 76 * state machine. 77 * @hide 78 */ 79 public class EntitlementManager { 80 private static final String TAG = EntitlementManager.class.getSimpleName(); 81 private static final boolean DBG = false; 82 83 @VisibleForTesting 84 protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning"; 85 @VisibleForTesting 86 protected static final String ACTION_PROVISIONING_ALARM = 87 "com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM"; 88 89 // Indicate tether provisioning is not required by carrier. 90 private static final int TETHERING_PROVISIONING_REQUIRED = 1000; 91 // Indicate tether provisioning is required by carrier. 92 private static final int TETHERING_PROVISIONING_NOT_REQUIRED = 1001; 93 // Indicate tethering is not supported by carrier. 94 private static final int TETHERING_PROVISIONING_CARRIER_UNSUPPORT = 1002; 95 96 private static final int MS_PER_HOUR = 60 * 60 * 1000; 97 private static final int DUMP_TIMEOUT = 10_000; 98 99 // The BitSet is the bit map of each enabled downstream types, ex: 100 // {@link TetheringManager.TETHERING_WIFI} 101 // {@link TetheringManager.TETHERING_USB} 102 // {@link TetheringManager.TETHERING_BLUETOOTH} 103 private final BitSet mCurrentDownstreams; 104 private final BitSet mExemptedDownstreams; 105 private final Context mContext; 106 private final SharedLog mLog; 107 private final SparseIntArray mEntitlementCacheValue; 108 private final Handler mHandler; 109 // Key: TetheringManager.TETHERING_*(downstream). 110 // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). 111 private final SparseIntArray mCurrentEntitlementResults; 112 private final Runnable mPermissionChangeCallback; 113 private PendingIntent mProvisioningRecheckAlarm; 114 private boolean mLastCellularUpstreamPermitted = true; 115 private boolean mUsingCellularAsUpstream = false; 116 private boolean mNeedReRunProvisioningUi = false; 117 private OnTetherProvisioningFailedListener mListener; 118 private TetheringConfigurationFetcher mFetcher; 119 private final Dependencies mDeps; 120 121 @VisibleForTesting(visibility = PRIVATE) 122 static class Dependencies { 123 @NonNull 124 private final Context mContext; 125 @NonNull 126 private final SharedLog mLog; 127 private final ComponentName mSilentProvisioningService; 128 Dependencies(@onNull Context context, @NonNull SharedLog log)129 Dependencies(@NonNull Context context, @NonNull SharedLog log) { 130 mContext = context; 131 mLog = log; 132 mSilentProvisioningService = ComponentName.unflattenFromString( 133 mContext.getResources().getString(R.string.config_wifi_tether_enable)); 134 } 135 136 /** 137 * Run the UI-enabled tethering provisioning check. 138 * @param type tethering type from TetheringManager.TETHERING_{@code *} 139 * @param receiver to receive entitlement check result. 140 * 141 * @return the broadcast intent, or null if the current user is not allowed to 142 * perform entitlement check. 143 */ 144 @Nullable runUiTetherProvisioning(int type, final TetheringConfiguration config, ResultReceiver receiver)145 protected Intent runUiTetherProvisioning(int type, final TetheringConfiguration config, 146 ResultReceiver receiver) { 147 if (DBG) mLog.i("runUiTetherProvisioning: " + type); 148 149 Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING_UI); 150 intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); 151 intent.putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, config.provisioningApp); 152 intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); 153 intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId); 154 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 155 156 // Only launch entitlement UI for the current user if it is allowed to 157 // change tethering. This usually means the system user or the admin users in HSUM. 158 if (SdkLevel.isAtLeastT()) { 159 // Create a user context for the current foreground user as UserManager#isAdmin() 160 // operates on the context user. 161 final int currentUserId = getCurrentUser(); 162 final UserHandle currentUser = UserHandle.of(currentUserId); 163 final Context userContext; 164 try { 165 // There is no safe way to invoke this method since tethering package 166 // might not be installed for a certain user on the OEM devices, 167 // refer to b/382628161. 168 userContext = mContext.createContextAsUser(currentUser, 0); 169 } catch (IllegalStateException e) { 170 FrameworkConnectivityStatsLog.write( 171 FrameworkConnectivityStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED, 172 FrameworkConnectivityStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED__ERROR_TYPE__TYPE_ENTITLEMENT_CREATE_CONTEXT_AS_USER_THROWS 173 ); 174 // Fallback to startActivity if createContextAsUser failed. 175 mLog.e("createContextAsUser failed, fallback to startActivity", e); 176 mContext.startActivity(intent); 177 return intent; 178 } 179 final UserManager userManager = userContext.getSystemService(UserManager.class); 180 181 if (userManager.isAdminUser()) { 182 mContext.startActivityAsUser(intent, currentUser); 183 } else { 184 mLog.e("Current user (" + currentUserId 185 + ") is not allowed to perform entitlement check."); 186 // If the user is not allowed to perform an entitlement check 187 // (e.g., a non-admin user), notify the receiver immediately. 188 // This is necessary because the entitlement check app cannot 189 // be launched to conduct the check and deliver the results. 190 receiver.send(TETHER_ERROR_PROVISIONING_FAILED, null); 191 return null; 192 } 193 } else { 194 // For T- devices, there is no other admin user other than the system user. 195 mContext.startActivity(intent); 196 } 197 return intent; 198 } 199 200 /** 201 * Run no UI tethering provisioning check. 202 * @param type tethering type from TetheringManager.TETHERING_{@code *} 203 */ runSilentTetherProvisioning( int type, final TetheringConfiguration config, ResultReceiver receiver)204 protected Intent runSilentTetherProvisioning( 205 int type, final TetheringConfiguration config, ResultReceiver receiver) { 206 if (DBG) mLog.i("runSilentTetherProvisioning: " + type); 207 208 Intent intent = new Intent(); 209 intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); 210 intent.putExtra(EXTRA_RUN_PROVISION, true); 211 intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, config.provisioningAppNoUi); 212 intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, config.provisioningResponse); 213 intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); 214 intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId); 215 intent.setComponent(mSilentProvisioningService); 216 // Only admin user can change tethering and SilentTetherProvisioning don't need to 217 // show UI, it is fine to always start setting's background service as system user. 218 mContext.startService(intent); 219 return intent; 220 } 221 222 /** 223 * Create a PendingIntent for the provisioning recheck alarm. 224 * @param pkgName the package name of the PendingIntent. 225 */ createRecheckAlarmIntent(final String pkgName)226 PendingIntent createRecheckAlarmIntent(final String pkgName) { 227 final Intent intent = new Intent(ACTION_PROVISIONING_ALARM); 228 intent.setPackage(pkgName); 229 return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); 230 } 231 232 /** 233 * Get the current user id. 234 */ getCurrentUser()235 int getCurrentUser() { 236 return ActivityManager.getCurrentUser(); 237 } 238 } 239 EntitlementManager(Context ctx, Handler h, SharedLog log, Runnable callback)240 public EntitlementManager(Context ctx, Handler h, SharedLog log, 241 Runnable callback) { 242 this(ctx, h, log, callback, new Dependencies(ctx, log)); 243 } 244 245 @VisibleForTesting(visibility = PRIVATE) EntitlementManager(Context ctx, Handler h, SharedLog log, Runnable callback, @NonNull Dependencies deps)246 EntitlementManager(Context ctx, Handler h, SharedLog log, 247 Runnable callback, @NonNull Dependencies deps) { 248 mContext = ctx; 249 mLog = log.forSubComponent(TAG); 250 mCurrentDownstreams = new BitSet(); 251 mExemptedDownstreams = new BitSet(); 252 mCurrentEntitlementResults = new SparseIntArray(); 253 mEntitlementCacheValue = new SparseIntArray(); 254 mPermissionChangeCallback = callback; 255 mHandler = h; 256 mDeps = deps; 257 if (SdkLevel.isAtLeastU()) { 258 mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM), 259 null, mHandler, RECEIVER_NOT_EXPORTED); 260 } else { 261 mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM), 262 null, mHandler); 263 } 264 } 265 setOnTetherProvisioningFailedListener( final OnTetherProvisioningFailedListener listener)266 public void setOnTetherProvisioningFailedListener( 267 final OnTetherProvisioningFailedListener listener) { 268 mListener = listener; 269 } 270 271 /** Callback fired when UI entitlement failed. */ 272 public interface OnTetherProvisioningFailedListener { 273 /** 274 * Ui entitlement check fails in |downstream|. 275 * 276 * @param downstream tethering type from TetheringManager.TETHERING_{@code *}. 277 * @param reason Failed reason. 278 */ onTetherProvisioningFailed(int downstream, String reason)279 void onTetherProvisioningFailed(int downstream, String reason); 280 } 281 setTetheringConfigurationFetcher(final TetheringConfigurationFetcher fetcher)282 public void setTetheringConfigurationFetcher(final TetheringConfigurationFetcher fetcher) { 283 mFetcher = fetcher; 284 } 285 286 /** Interface to fetch TetheringConfiguration. */ 287 public interface TetheringConfigurationFetcher { 288 /** 289 * Fetch current tethering configuration. This will be called to ensure whether entitlement 290 * check is needed. 291 * @return TetheringConfiguration instance. 292 */ fetchTetheringConfiguration()293 TetheringConfiguration fetchTetheringConfiguration(); 294 } 295 296 /** 297 * Check if cellular upstream is permitted. 298 */ isCellularUpstreamPermitted()299 public boolean isCellularUpstreamPermitted() { 300 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); 301 302 return isCellularUpstreamPermitted(config); 303 } 304 isCellularUpstreamPermitted(final TetheringConfiguration config)305 private boolean isCellularUpstreamPermitted(final TetheringConfiguration config) { 306 // If #getTetherProvisioningCondition return TETHERING_PROVISIONING_CARRIER_UNSUPPORT, 307 // that means cellular upstream is not supported and entitlement check result is empty 308 // because entitlement check should not be run. 309 if (!isTetherProvisioningRequired(config)) return true; 310 311 // If provisioning is required and EntitlementManager doesn't know any downstreams, cellular 312 // upstream should not be enabled. Enable cellular upstream for exempted downstreams only 313 // when there is no non-exempted downstream. 314 if (mCurrentDownstreams.isEmpty()) return !mExemptedDownstreams.isEmpty(); 315 316 return mCurrentEntitlementResults.indexOfValue(TETHER_ERROR_NO_ERROR) > -1; 317 } 318 319 /** 320 * Set exempted downstream type. If there is only exempted downstream type active, 321 * corresponding entitlement check will not be run and cellular upstream will be permitted 322 * by default. If a privileged app enables tethering without a provisioning check, and then 323 * another app enables tethering of the same type but does not disable the provisioning check, 324 * then the downstream immediately loses exempt status and a provisioning check is run. 325 * If any non-exempted downstream type is active, the cellular upstream will be gated by the 326 * result of entitlement check from non-exempted downstreams. If entitlement check is still 327 * in progress on non-exempt downstreams, ceullar upstream would default be disabled. When any 328 * non-exempted downstream gets positive entitlement result, ceullar upstream will be enabled. 329 */ setExemptedDownstreamType(final int type)330 public void setExemptedDownstreamType(final int type) { 331 mExemptedDownstreams.set(type, true); 332 } 333 334 /** 335 * This is called when tethering starts. 336 * Launch provisioning app if upstream is cellular. 337 * 338 * @param downstreamType tethering type from TetheringManager.TETHERING_{@code *} 339 * @param showProvisioningUi a boolean indicating whether to show the 340 * provisioning app UI if there is one. 341 */ startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi)342 public void startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi) { 343 if (!isValidDownstreamType(downstreamType)) return; 344 345 mCurrentDownstreams.set(downstreamType, true); 346 347 mExemptedDownstreams.set(downstreamType, false); 348 349 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); 350 if (!isTetherProvisioningRequired(config)) return; 351 352 // If upstream is not cellular, provisioning app would not be launched 353 // till upstream change to cellular. 354 if (mUsingCellularAsUpstream) { 355 runTetheringProvisioning(showProvisioningUi, downstreamType, config); 356 mNeedReRunProvisioningUi = false; 357 } else { 358 mNeedReRunProvisioningUi |= showProvisioningUi; 359 } 360 } 361 362 /** 363 * Tell EntitlementManager that a given type of tethering has been disabled 364 * 365 * @param type tethering type from TetheringManager.TETHERING_{@code *} 366 */ stopProvisioningIfNeeded(int downstreamType)367 public void stopProvisioningIfNeeded(int downstreamType) { 368 if (!isValidDownstreamType(downstreamType)) return; 369 370 mCurrentDownstreams.set(downstreamType, false); 371 // There are lurking bugs where the notion of "provisioning required" or 372 // "tethering supported" may change without without tethering being notified properly. 373 // Remove the mapping all the time no matter provisioning is required or not. 374 removeDownstreamMapping(downstreamType); 375 mExemptedDownstreams.set(downstreamType, false); 376 } 377 378 /** 379 * Notify EntitlementManager if upstream is cellular or not. 380 * 381 * @param isCellular whether tethering upstream is cellular. 382 */ notifyUpstream(boolean isCellular)383 public void notifyUpstream(boolean isCellular) { 384 if (DBG) { 385 mLog.i("notifyUpstream: " + isCellular 386 + ", mLastCellularUpstreamPermitted: " + mLastCellularUpstreamPermitted 387 + ", mNeedReRunProvisioningUi: " + mNeedReRunProvisioningUi); 388 } 389 mUsingCellularAsUpstream = isCellular; 390 391 if (mUsingCellularAsUpstream) { 392 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); 393 maybeRunProvisioning(config); 394 } 395 } 396 397 /** Run provisioning if needed */ maybeRunProvisioning()398 public void maybeRunProvisioning() { 399 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); 400 maybeRunProvisioning(config); 401 } 402 maybeRunProvisioning(final TetheringConfiguration config)403 private void maybeRunProvisioning(final TetheringConfiguration config) { 404 if (mCurrentDownstreams.isEmpty() || !isTetherProvisioningRequired(config)) { 405 return; 406 } 407 408 // Whenever any entitlement value changes, all downstreams will re-evaluate whether they 409 // are allowed. Therefore even if the silent check here ends in a failure and the UI later 410 // yields success, then the downstream that got a failure will re-evaluate as a result of 411 // the change and get the new correct value. 412 for (int downstream = mCurrentDownstreams.nextSetBit(0); downstream >= 0; 413 downstream = mCurrentDownstreams.nextSetBit(downstream + 1)) { 414 // If tethering provisioning is required but entitlement check result is empty, 415 // this means tethering may need to run entitlement check or carrier network 416 // is not supported. 417 if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) { 418 runTetheringProvisioning(mNeedReRunProvisioningUi, downstream, config); 419 mNeedReRunProvisioningUi = false; 420 } 421 } 422 } 423 424 /** 425 * Tether provisioning has these conditions to control provisioning behavior. 426 * 1st priority : Uses system property to disable any provisioning behavior. 427 * 2nd priority : Uses {@code CarrierConfigManager#KEY_CARRIER_SUPPORTS_TETHERING_BOOL} to 428 * decide current carrier support cellular upstream tethering or not. 429 * If value is true, it means check follow up condition to know whether 430 * provisioning is required. 431 * If value is false, it means tethering could not use cellular as upstream. 432 * 3rd priority : Uses {@code CarrierConfigManager#KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL} to 433 * decide current carrier require the provisioning. 434 * 4th priority : Checks whether provisioning is required from RRO configuration. 435 * 436 * @param config 437 * @return integer See {@link #TETHERING_PROVISIONING_NOT_REQUIRED, 438 * #TETHERING_PROVISIONING_REQUIRED, 439 * #TETHERING_PROVISIONING_CARRIER_UNSUPPORT} 440 */ getTetherProvisioningCondition(final TetheringConfiguration config)441 private int getTetherProvisioningCondition(final TetheringConfiguration config) { 442 if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)) { 443 return TETHERING_PROVISIONING_NOT_REQUIRED; 444 } 445 446 if (!config.isCarrierSupportTethering) { 447 // To block tethering, behave as if running provisioning check and failed. 448 return TETHERING_PROVISIONING_CARRIER_UNSUPPORT; 449 } 450 451 if (!config.isCarrierConfigAffirmsEntitlementCheckRequired) { 452 return TETHERING_PROVISIONING_NOT_REQUIRED; 453 } 454 return (config.provisioningApp.length == 2) 455 ? TETHERING_PROVISIONING_REQUIRED : TETHERING_PROVISIONING_NOT_REQUIRED; 456 } 457 458 /** 459 * Check if the device requires a provisioning check in order to enable tethering. 460 * 461 * @param config an object that encapsulates the various tethering configuration elements. 462 * @return a boolean - {@code true} indicating tether provisioning is required by the carrier. 463 */ 464 @VisibleForTesting isTetherProvisioningRequired(final TetheringConfiguration config)465 protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) { 466 return getTetherProvisioningCondition(config) != TETHERING_PROVISIONING_NOT_REQUIRED; 467 } 468 469 /** 470 * Confirms the need of tethering provisioning but no entitlement package exists. 471 */ isProvisioningNeededButUnavailable()472 public boolean isProvisioningNeededButUnavailable() { 473 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); 474 return getTetherProvisioningCondition(config) == TETHERING_PROVISIONING_REQUIRED 475 && !doesEntitlementPackageExist(config); 476 } 477 doesEntitlementPackageExist(final TetheringConfiguration config)478 private boolean doesEntitlementPackageExist(final TetheringConfiguration config) { 479 final PackageManager pm = mContext.getPackageManager(); 480 try { 481 pm.getPackageInfo(config.provisioningApp[0], GET_ACTIVITIES); 482 } catch (PackageManager.NameNotFoundException e) { 483 return false; 484 } 485 return true; 486 } 487 488 /** 489 * Re-check tethering provisioning for all enabled tether types. 490 * Reference TetheringManager.TETHERING_{@code *} for each tether type. 491 * 492 * @param config an object that encapsulates the various tethering configuration elements. 493 * Note: this method is only called from @{link Tethering.TetherMainSM} on the handler thread. 494 * If there are new callers from different threads, the logic should move to 495 * @{link Tethering.TetherMainSM} handler to avoid race conditions. 496 */ reevaluateSimCardProvisioning(final TetheringConfiguration config)497 public void reevaluateSimCardProvisioning(final TetheringConfiguration config) { 498 if (DBG) mLog.i("reevaluateSimCardProvisioning"); 499 500 if (!mHandler.getLooper().isCurrentThread()) { 501 // Except for test, this log should not appear in normal flow. 502 mLog.log("reevaluateSimCardProvisioning() don't run in TetherMainSM thread"); 503 } 504 mEntitlementCacheValue.clear(); 505 mCurrentEntitlementResults.clear(); 506 507 if (!isTetherProvisioningRequired(config)) { 508 evaluateCellularPermission(config); 509 return; 510 } 511 512 if (mUsingCellularAsUpstream) { 513 maybeRunProvisioning(config); 514 } 515 } 516 runTetheringProvisioning( boolean showProvisioningUi, int downstreamType, final TetheringConfiguration config)517 private void runTetheringProvisioning( 518 boolean showProvisioningUi, int downstreamType, final TetheringConfiguration config) { 519 if (!config.isCarrierSupportTethering) { 520 mListener.onTetherProvisioningFailed(downstreamType, "Carrier does not support."); 521 if (showProvisioningUi) { 522 showCarrierUnsupportedDialog(); 523 } 524 return; 525 } 526 527 ResultReceiver receiver = 528 buildProxyReceiver(downstreamType, showProvisioningUi/* notifyFail */, null); 529 if (showProvisioningUi) { 530 mDeps.runUiTetherProvisioning(downstreamType, config, receiver); 531 } else { 532 mDeps.runSilentTetherProvisioning(downstreamType, config, receiver); 533 } 534 } 535 showCarrierUnsupportedDialog()536 private void showCarrierUnsupportedDialog() { 537 // This is only used when TetheringConfiguration.isCarrierSupportTethering is false. 538 if (!SdkLevel.isAtLeastT()) { 539 return; 540 } 541 Intent intent = new Intent(ACTION_TETHER_UNSUPPORTED_CARRIER_UI); 542 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 543 mContext.startActivity(intent); 544 } 545 546 // Not needed to check if this don't run on the handler thread because it's private. scheduleProvisioningRecheck(final TetheringConfiguration config)547 private void scheduleProvisioningRecheck(final TetheringConfiguration config) { 548 if (mProvisioningRecheckAlarm == null) { 549 final int period = config.provisioningCheckPeriod; 550 if (period <= 0) return; 551 552 mProvisioningRecheckAlarm = mDeps.createRecheckAlarmIntent(mContext.getPackageName()); 553 AlarmManager alarmManager = (AlarmManager) mContext.getSystemService( 554 Context.ALARM_SERVICE); 555 long triggerAtMillis = SystemClock.elapsedRealtime() + (period * MS_PER_HOUR); 556 alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, 557 mProvisioningRecheckAlarm); 558 } 559 } 560 cancelTetherProvisioningRechecks()561 private void cancelTetherProvisioningRechecks() { 562 if (mProvisioningRecheckAlarm != null) { 563 AlarmManager alarmManager = (AlarmManager) mContext.getSystemService( 564 Context.ALARM_SERVICE); 565 alarmManager.cancel(mProvisioningRecheckAlarm); 566 mProvisioningRecheckAlarm = null; 567 } 568 } 569 rescheduleProvisioningRecheck(final TetheringConfiguration config)570 private void rescheduleProvisioningRecheck(final TetheringConfiguration config) { 571 cancelTetherProvisioningRechecks(); 572 scheduleProvisioningRecheck(config); 573 } 574 evaluateCellularPermission(final TetheringConfiguration config)575 private void evaluateCellularPermission(final TetheringConfiguration config) { 576 final boolean permitted = isCellularUpstreamPermitted(config); 577 578 if (DBG) { 579 mLog.i("Cellular permission change from " + mLastCellularUpstreamPermitted 580 + " to " + permitted); 581 } 582 583 if (mLastCellularUpstreamPermitted != permitted) { 584 mLog.log("Cellular permission change: " + permitted); 585 mPermissionChangeCallback.run(); 586 } 587 // Only schedule periodic re-check when tether is provisioned 588 // and the result is ok. 589 if (permitted && mCurrentEntitlementResults.size() > 0) { 590 scheduleProvisioningRecheck(config); 591 } else { 592 cancelTetherProvisioningRechecks(); 593 } 594 mLastCellularUpstreamPermitted = permitted; 595 } 596 597 /** 598 * Add the mapping between provisioning result and tethering type. 599 * Notify UpstreamNetworkMonitor if Cellular permission changes. 600 * 601 * @param type tethering type from TetheringManager.TETHERING_{@code *} 602 * @param resultCode Provisioning result 603 */ addDownstreamMapping(int type, int resultCode)604 protected void addDownstreamMapping(int type, int resultCode) { 605 mLog.i("addDownstreamMapping: " + type + ", result: " + resultCode 606 + " ,TetherTypeRequested: " + mCurrentDownstreams.get(type)); 607 if (!mCurrentDownstreams.get(type)) return; 608 609 mCurrentEntitlementResults.put(type, resultCode); 610 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); 611 evaluateCellularPermission(config); 612 } 613 614 /** 615 * Remove the mapping for input tethering type. 616 * @param type tethering type from TetheringManager.TETHERING_{@code *} 617 */ removeDownstreamMapping(int type)618 protected void removeDownstreamMapping(int type) { 619 mLog.i("removeDownstreamMapping: " + type); 620 mCurrentEntitlementResults.delete(type); 621 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); 622 evaluateCellularPermission(config); 623 } 624 625 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 626 @Override 627 public void onReceive(Context context, Intent intent) { 628 if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) { 629 mLog.log("Received provisioning alarm"); 630 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); 631 rescheduleProvisioningRecheck(config); 632 reevaluateSimCardProvisioning(config); 633 } 634 } 635 }; 636 isValidDownstreamType(int type)637 private static boolean isValidDownstreamType(int type) { 638 switch (type) { 639 case TETHERING_BLUETOOTH: 640 case TETHERING_ETHERNET: 641 case TETHERING_USB: 642 case TETHERING_WIFI: 643 return true; 644 default: 645 return false; 646 } 647 } 648 649 /** 650 * Dump the infromation of EntitlementManager. 651 * @param pw {@link PrintWriter} is used to print formatted 652 */ dump(PrintWriter pw)653 public void dump(PrintWriter pw) { 654 pw.print("isCellularUpstreamPermitted: "); 655 pw.println(isCellularUpstreamPermitted()); 656 for (int type = mCurrentDownstreams.nextSetBit(0); type >= 0; 657 type = mCurrentDownstreams.nextSetBit(type + 1)) { 658 pw.print("Type: "); 659 pw.print(typeString(type)); 660 if (mCurrentEntitlementResults.indexOfKey(type) > -1) { 661 pw.print(", Value: "); 662 pw.println(errorString(mCurrentEntitlementResults.get(type))); 663 } else { 664 pw.println(", Value: empty"); 665 } 666 } 667 pw.print("Exempted: ["); 668 for (int type = mExemptedDownstreams.nextSetBit(0); type >= 0; 669 type = mExemptedDownstreams.nextSetBit(type + 1)) { 670 pw.print(typeString(type)); 671 pw.print(", "); 672 } 673 pw.println("]"); 674 } 675 typeString(int type)676 private static String typeString(int type) { 677 switch (type) { 678 case TETHERING_BLUETOOTH: return "TETHERING_BLUETOOTH"; 679 case TETHERING_INVALID: return "TETHERING_INVALID"; 680 case TETHERING_USB: return "TETHERING_USB"; 681 case TETHERING_WIFI: return "TETHERING_WIFI"; 682 default: 683 return String.format("TETHERING UNKNOWN TYPE (%d)", type); 684 } 685 } 686 errorString(int value)687 private static String errorString(int value) { 688 switch (value) { 689 case TETHER_ERROR_ENTITLEMENT_UNKNOWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN"; 690 case TETHER_ERROR_NO_ERROR: return "TETHER_ERROR_NO_ERROR"; 691 case TETHER_ERROR_PROVISIONING_FAILED: return "TETHER_ERROR_PROVISIONING_FAILED"; 692 default: 693 return String.format("UNKNOWN ERROR (%d)", value); 694 } 695 } 696 buildProxyReceiver(int type, boolean notifyFail, final ResultReceiver receiver)697 private ResultReceiver buildProxyReceiver(int type, boolean notifyFail, 698 final ResultReceiver receiver) { 699 ResultReceiver rr = new ResultReceiver(mHandler) { 700 @Override 701 protected void onReceiveResult(int resultCode, Bundle resultData) { 702 int updatedCacheValue = updateEntitlementCacheValue(type, resultCode); 703 addDownstreamMapping(type, updatedCacheValue); 704 if (updatedCacheValue == TETHER_ERROR_PROVISIONING_FAILED && notifyFail) { 705 mListener.onTetherProvisioningFailed( 706 type, "Tethering provisioning failed."); 707 } 708 if (receiver != null) receiver.send(updatedCacheValue, null); 709 } 710 }; 711 712 return writeToParcel(rr); 713 } 714 715 // Instances of ResultReceiver need to be public classes for remote processes to be able 716 // to load them (otherwise, ClassNotFoundException). For private classes, this method 717 // performs a trick : round-trip parceling any instance of ResultReceiver will return a 718 // vanilla instance of ResultReceiver sharing the binder token with the original receiver. 719 // The binder token has a reference to the original instance of the private class and will 720 // still call its methods, and can be sent over. However it cannot be used for anything 721 // else than sending over a Binder call. 722 // While round-trip parceling is not great, there is currently no other way of generating 723 // a vanilla instance of ResultReceiver because all its fields are private. writeToParcel(final ResultReceiver receiver)724 private ResultReceiver writeToParcel(final ResultReceiver receiver) { 725 Parcel parcel = Parcel.obtain(); 726 receiver.writeToParcel(parcel, 0); 727 parcel.setDataPosition(0); 728 ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel); 729 parcel.recycle(); 730 return receiverForSending; 731 } 732 733 /** 734 * Update the last entitlement value to internal cache 735 * 736 * @param type tethering type from TetheringManager.TETHERING_{@code *} 737 * @param resultCode last entitlement value 738 * @return the last updated entitlement value 739 */ updateEntitlementCacheValue(int type, int resultCode)740 private int updateEntitlementCacheValue(int type, int resultCode) { 741 if (DBG) { 742 mLog.i("updateEntitlementCacheValue: " + type + ", result: " + resultCode); 743 } 744 if (resultCode == TETHER_ERROR_NO_ERROR) { 745 mEntitlementCacheValue.put(type, resultCode); 746 return resultCode; 747 } else { 748 mEntitlementCacheValue.put(type, TETHER_ERROR_PROVISIONING_FAILED); 749 return TETHER_ERROR_PROVISIONING_FAILED; 750 } 751 } 752 753 /** Get the last value of the tethering entitlement check. */ requestLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver, boolean showEntitlementUi)754 public void requestLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver, 755 boolean showEntitlementUi) { 756 if (!isValidDownstreamType(downstream)) { 757 receiver.send(TETHER_ERROR_ENTITLEMENT_UNKNOWN, null); 758 return; 759 } 760 761 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); 762 763 switch (getTetherProvisioningCondition(config)) { 764 case TETHERING_PROVISIONING_NOT_REQUIRED: 765 receiver.send(TETHER_ERROR_NO_ERROR, null); 766 return; 767 case TETHERING_PROVISIONING_CARRIER_UNSUPPORT: 768 receiver.send(TETHER_ERROR_PROVISIONING_FAILED, null); 769 return; 770 } 771 772 final int cacheValue = mEntitlementCacheValue.get( 773 downstream, TETHER_ERROR_ENTITLEMENT_UNKNOWN); 774 if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) { 775 receiver.send(cacheValue, null); 776 } else { 777 ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver); 778 mDeps.runUiTetherProvisioning(downstream, config, proxy); 779 } 780 } 781 } 782