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