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