• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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