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