blob: ba5d08dce4cac2e32c9c568a4b7ab2587bf2ecf5 [file] [log] [blame]
markchienb6eb2c22018-07-18 14:29:20 +08001/*
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
17package com.android.server.connectivity.tethering;
18
19import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
20import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
markchienb6eb2c22018-07-18 14:29:20 +080021import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
markchien3b519632018-09-07 16:19:12 +080022import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
23import static android.net.ConnectivityManager.TETHERING_INVALID;
24import static android.net.ConnectivityManager.TETHERING_USB;
25import static android.net.ConnectivityManager.TETHERING_WIFI;
markchienf2731272019-01-16 17:44:13 +080026import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
27import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
28import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
markchienb6eb2c22018-07-18 14:29:20 +080029
30import static com.android.internal.R.string.config_wifi_tether_enable;
31
markchien3b519632018-09-07 16:19:12 +080032import android.app.AlarmManager;
33import android.app.PendingIntent;
34import android.content.BroadcastReceiver;
markchienb6eb2c22018-07-18 14:29:20 +080035import android.content.ComponentName;
36import android.content.Context;
37import android.content.Intent;
markchien3b519632018-09-07 16:19:12 +080038import android.content.IntentFilter;
markchienb6eb2c22018-07-18 14:29:20 +080039import android.content.res.Resources;
40import android.net.util.SharedLog;
41import android.os.Binder;
markchienf2731272019-01-16 17:44:13 +080042import android.os.Bundle;
43import android.os.Handler;
markchien3b519632018-09-07 16:19:12 +080044import android.os.Looper;
45import android.os.Message;
markchienf2731272019-01-16 17:44:13 +080046import android.os.Parcel;
markchienb6eb2c22018-07-18 14:29:20 +080047import android.os.PersistableBundle;
48import android.os.ResultReceiver;
markchien3b519632018-09-07 16:19:12 +080049import android.os.SystemClock;
markchien0df2ebc42019-09-30 14:40:57 +080050import android.os.SystemProperties;
markchienb6eb2c22018-07-18 14:29:20 +080051import android.os.UserHandle;
52import android.provider.Settings;
53import android.telephony.CarrierConfigManager;
54import android.util.ArraySet;
markchienf2731272019-01-16 17:44:13 +080055import android.util.SparseIntArray;
markchienb6eb2c22018-07-18 14:29:20 +080056
markchienb6eb2c22018-07-18 14:29:20 +080057import com.android.internal.annotations.VisibleForTesting;
markchienf2731272019-01-16 17:44:13 +080058import com.android.internal.util.StateMachine;
markchienb6eb2c22018-07-18 14:29:20 +080059
markchien3b519632018-09-07 16:19:12 +080060import java.io.PrintWriter;
61
markchienb6eb2c22018-07-18 14:29:20 +080062/**
markchien3b519632018-09-07 16:19:12 +080063 * Re-check tethering provisioning for enabled downstream tether types.
64 * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
markchienb6eb2c22018-07-18 14:29:20 +080065 *
markchien3b519632018-09-07 16:19:12 +080066 * All methods of this class must be accessed from the thread of tethering
67 * state machine.
markchienb6eb2c22018-07-18 14:29:20 +080068 * @hide
69 */
70public class EntitlementManager {
71 private static final String TAG = EntitlementManager.class.getSimpleName();
markchienf2731272019-01-16 17:44:13 +080072 private static final boolean DBG = false;
markchienb6eb2c22018-07-18 14:29:20 +080073
markchien3b519632018-09-07 16:19:12 +080074 @VisibleForTesting
75 protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
76 private static final String ACTION_PROVISIONING_ALARM =
77 "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM";
markchien3394e142019-04-09 15:53:24 +080078 private static final String EXTRA_SUBID = "subId";
markchien3b519632018-09-07 16:19:12 +080079
markchienb6eb2c22018-07-18 14:29:20 +080080 // {@link ComponentName} of the Service used to run tether provisioning.
81 private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(
82 Resources.getSystem().getString(config_wifi_tether_enable));
markchien3b519632018-09-07 16:19:12 +080083 private static final int MS_PER_HOUR = 60 * 60 * 1000;
84 private static final int EVENT_START_PROVISIONING = 0;
85 private static final int EVENT_STOP_PROVISIONING = 1;
86 private static final int EVENT_UPSTREAM_CHANGED = 2;
87 private static final int EVENT_MAYBE_RUN_PROVISIONING = 3;
88 private static final int EVENT_GET_ENTITLEMENT_VALUE = 4;
89
markchienb6eb2c22018-07-18 14:29:20 +080090 // The ArraySet contains enabled downstream types, ex:
91 // {@link ConnectivityManager.TETHERING_WIFI}
92 // {@link ConnectivityManager.TETHERING_USB}
93 // {@link ConnectivityManager.TETHERING_BLUETOOTH}
markchienb6eb2c22018-07-18 14:29:20 +080094 private final ArraySet<Integer> mCurrentTethers;
95 private final Context mContext;
markchien3b519632018-09-07 16:19:12 +080096 private final int mPermissionChangeMessageCode;
markchienb6eb2c22018-07-18 14:29:20 +080097 private final SharedLog mLog;
markchienf2731272019-01-16 17:44:13 +080098 private final SparseIntArray mEntitlementCacheValue;
markchien3b519632018-09-07 16:19:12 +080099 private final EntitlementHandler mHandler;
markchien3b519632018-09-07 16:19:12 +0800100 private final StateMachine mTetherMasterSM;
101 // Key: ConnectivityManager.TETHERING_*(downstream).
102 // Value: ConnectivityManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
103 private final SparseIntArray mCellularPermitted;
104 private PendingIntent mProvisioningRecheckAlarm;
105 private boolean mCellularUpstreamPermitted = true;
106 private boolean mUsingCellularAsUpstream = false;
107 private boolean mNeedReRunProvisioningUi = false;
markchien29b70142019-03-26 21:41:59 +0800108 private OnUiEntitlementFailedListener mListener;
markchien3394e142019-04-09 15:53:24 +0800109 private TetheringConfigurationFetcher mFetcher;
markchienb6eb2c22018-07-18 14:29:20 +0800110
markchienf2731272019-01-16 17:44:13 +0800111 public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
markchien0df2ebc42019-09-30 14:40:57 +0800112 int permissionChangeMessageCode) {
113
markchienb6eb2c22018-07-18 14:29:20 +0800114 mContext = ctx;
markchienf2731272019-01-16 17:44:13 +0800115 mLog = log.forSubComponent(TAG);
markchienb6eb2c22018-07-18 14:29:20 +0800116 mCurrentTethers = new ArraySet<Integer>();
markchien3b519632018-09-07 16:19:12 +0800117 mCellularPermitted = new SparseIntArray();
markchienf2731272019-01-16 17:44:13 +0800118 mEntitlementCacheValue = new SparseIntArray();
markchien3b519632018-09-07 16:19:12 +0800119 mTetherMasterSM = tetherMasterSM;
120 mPermissionChangeMessageCode = permissionChangeMessageCode;
121 final Handler masterHandler = tetherMasterSM.getHandler();
122 // Create entitlement's own handler which is associated with TetherMaster thread
123 // let all entitlement processes run in the same thread.
124 mHandler = new EntitlementHandler(masterHandler.getLooper());
125 mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM),
126 null, mHandler);
markchienb6eb2c22018-07-18 14:29:20 +0800127 }
128
markchien29b70142019-03-26 21:41:59 +0800129 public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
130 mListener = listener;
131 }
132
133 /** Callback fired when UI entitlement failed. */
134 public interface OnUiEntitlementFailedListener {
135 /**
136 * Ui entitlement check fails in |downstream|.
137 *
markchienf303c5a2019-09-23 20:29:54 +0800138 * @param downstream tethering type from ConnectivityManager.TETHERING_{@code *}.
markchien29b70142019-03-26 21:41:59 +0800139 */
140 void onUiEntitlementFailed(int downstream);
141 }
142
markchien3394e142019-04-09 15:53:24 +0800143 public void setTetheringConfigurationFetcher(final TetheringConfigurationFetcher fetcher) {
144 mFetcher = fetcher;
145 }
146
147 /** Interface to fetch TetheringConfiguration. */
148 public interface TetheringConfigurationFetcher {
149 /**
150 * Fetch current tethering configuration. This will be called to ensure whether entitlement
151 * check is needed.
152 * @return TetheringConfiguration instance.
153 */
154 TetheringConfiguration fetchTetheringConfiguration();
markchienb6eb2c22018-07-18 14:29:20 +0800155 }
156
157 /**
markchien3b519632018-09-07 16:19:12 +0800158 * Check if cellular upstream is permitted.
markchienb6eb2c22018-07-18 14:29:20 +0800159 */
markchien3b519632018-09-07 16:19:12 +0800160 public boolean isCellularUpstreamPermitted() {
markchien426311b2019-08-09 21:43:38 +0800161 // If provisioning is required and EntitlementManager don't know any downstream,
162 // cellular upstream should not be allowed.
163 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
164 if (mCurrentTethers.size() == 0 && isTetherProvisioningRequired(config)) {
165 return false;
166 }
markchien3b519632018-09-07 16:19:12 +0800167 return mCellularUpstreamPermitted;
168 }
169
170 /**
171 * This is called when tethering starts.
172 * Launch provisioning app if upstream is cellular.
173 *
174 * @param downstreamType tethering type from ConnectivityManager.TETHERING_{@code *}
175 * @param showProvisioningUi a boolean indicating whether to show the
176 * provisioning app UI if there is one.
177 */
178 public void startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi) {
179 mHandler.sendMessage(mHandler.obtainMessage(EVENT_START_PROVISIONING,
180 downstreamType, encodeBool(showProvisioningUi)));
181 }
182
183 private void handleStartProvisioningIfNeeded(int type, boolean showProvisioningUi) {
184 if (!isValidDownstreamType(type)) return;
185
186 if (!mCurrentTethers.contains(type)) mCurrentTethers.add(type);
187
markchien3394e142019-04-09 15:53:24 +0800188 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
189 if (isTetherProvisioningRequired(config)) {
markchien3b519632018-09-07 16:19:12 +0800190 // If provisioning is required and the result is not available yet,
191 // cellular upstream should not be allowed.
192 if (mCellularPermitted.size() == 0) {
193 mCellularUpstreamPermitted = false;
194 }
195 // If upstream is not cellular, provisioning app would not be launched
196 // till upstream change to cellular.
197 if (mUsingCellularAsUpstream) {
198 if (showProvisioningUi) {
markchien3394e142019-04-09 15:53:24 +0800199 runUiTetherProvisioning(type, config.subId);
markchien3b519632018-09-07 16:19:12 +0800200 } else {
markchien3394e142019-04-09 15:53:24 +0800201 runSilentTetherProvisioning(type, config.subId);
markchien3b519632018-09-07 16:19:12 +0800202 }
203 mNeedReRunProvisioningUi = false;
204 } else {
205 mNeedReRunProvisioningUi |= showProvisioningUi;
206 }
207 } else {
208 mCellularUpstreamPermitted = true;
markchienb6eb2c22018-07-18 14:29:20 +0800209 }
210 }
211
212 /**
213 * Tell EntitlementManager that a given type of tethering has been disabled
214 *
markchien3b519632018-09-07 16:19:12 +0800215 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
markchienb6eb2c22018-07-18 14:29:20 +0800216 */
markchien3b519632018-09-07 16:19:12 +0800217 public void stopProvisioningIfNeeded(int type) {
218 mHandler.sendMessage(mHandler.obtainMessage(EVENT_STOP_PROVISIONING, type, 0));
219 }
220
221 private void handleStopProvisioningIfNeeded(int type) {
222 if (!isValidDownstreamType(type)) return;
223
224 mCurrentTethers.remove(type);
225 // There are lurking bugs where the notion of "provisioning required" or
226 // "tethering supported" may change without without tethering being notified properly.
227 // Remove the mapping all the time no matter provisioning is required or not.
228 removeDownstreamMapping(type);
229 }
230
231 /**
232 * Notify EntitlementManager if upstream is cellular or not.
233 *
234 * @param isCellular whether tethering upstream is cellular.
235 */
236 public void notifyUpstream(boolean isCellular) {
237 mHandler.sendMessage(mHandler.obtainMessage(
238 EVENT_UPSTREAM_CHANGED, encodeBool(isCellular), 0));
239 }
240
241 private void handleNotifyUpstream(boolean isCellular) {
242 if (DBG) {
markchien9f246bd2019-04-03 10:43:09 +0800243 mLog.i("notifyUpstream: " + isCellular
markchien3b519632018-09-07 16:19:12 +0800244 + ", mCellularUpstreamPermitted: " + mCellularUpstreamPermitted
245 + ", mNeedReRunProvisioningUi: " + mNeedReRunProvisioningUi);
246 }
247 mUsingCellularAsUpstream = isCellular;
248
249 if (mUsingCellularAsUpstream) {
markchien3394e142019-04-09 15:53:24 +0800250 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
251 handleMaybeRunProvisioning(config);
markchien3b519632018-09-07 16:19:12 +0800252 }
253 }
254
255 /** Run provisioning if needed */
256 public void maybeRunProvisioning() {
257 mHandler.sendMessage(mHandler.obtainMessage(EVENT_MAYBE_RUN_PROVISIONING));
258 }
259
markchien3394e142019-04-09 15:53:24 +0800260 private void handleMaybeRunProvisioning(final TetheringConfiguration config) {
261 if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired(config)) {
markchien3b519632018-09-07 16:19:12 +0800262 return;
263 }
264
265 // Whenever any entitlement value changes, all downstreams will re-evaluate whether they
266 // are allowed. Therefore even if the silent check here ends in a failure and the UI later
267 // yields success, then the downstream that got a failure will re-evaluate as a result of
268 // the change and get the new correct value.
269 for (Integer downstream : mCurrentTethers) {
270 if (mCellularPermitted.indexOfKey(downstream) < 0) {
271 if (mNeedReRunProvisioningUi) {
272 mNeedReRunProvisioningUi = false;
markchien3394e142019-04-09 15:53:24 +0800273 runUiTetherProvisioning(downstream, config.subId);
markchien3b519632018-09-07 16:19:12 +0800274 } else {
markchien3394e142019-04-09 15:53:24 +0800275 runSilentTetherProvisioning(downstream, config.subId);
markchien3b519632018-09-07 16:19:12 +0800276 }
277 }
markchienb6eb2c22018-07-18 14:29:20 +0800278 }
279 }
280
281 /**
282 * Check if the device requires a provisioning check in order to enable tethering.
283 *
markchien3394e142019-04-09 15:53:24 +0800284 * @param config an object that encapsulates the various tethering configuration elements.
markchienb6eb2c22018-07-18 14:29:20 +0800285 * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
286 */
287 @VisibleForTesting
markchien3394e142019-04-09 15:53:24 +0800288 protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) {
markchien0df2ebc42019-09-30 14:40:57 +0800289 if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
markchien3394e142019-04-09 15:53:24 +0800290 || config.provisioningApp.length == 0) {
markchienb6eb2c22018-07-18 14:29:20 +0800291 return false;
292 }
markchien3394e142019-04-09 15:53:24 +0800293 if (carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
markchienb6eb2c22018-07-18 14:29:20 +0800294 return false;
295 }
markchien3394e142019-04-09 15:53:24 +0800296 return (config.provisioningApp.length == 2);
markchienb6eb2c22018-07-18 14:29:20 +0800297 }
298
299 /**
markchien3b519632018-09-07 16:19:12 +0800300 * Re-check tethering provisioning for all enabled tether types.
markchienb6eb2c22018-07-18 14:29:20 +0800301 * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
markchien3b519632018-09-07 16:19:12 +0800302 *
markchien3394e142019-04-09 15:53:24 +0800303 * @param config an object that encapsulates the various tethering configuration elements.
markchien3b519632018-09-07 16:19:12 +0800304 * Note: this method is only called from TetherMaster on the handler thread.
305 * If there are new callers from different threads, the logic should move to
306 * masterHandler to avoid race conditions.
markchienb6eb2c22018-07-18 14:29:20 +0800307 */
markchien3394e142019-04-09 15:53:24 +0800308 public void reevaluateSimCardProvisioning(final TetheringConfiguration config) {
markchien9f246bd2019-04-03 10:43:09 +0800309 if (DBG) mLog.i("reevaluateSimCardProvisioning");
markchien3b519632018-09-07 16:19:12 +0800310
311 if (!mHandler.getLooper().isCurrentThread()) {
312 // Except for test, this log should not appear in normal flow.
313 mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread");
314 }
315 mEntitlementCacheValue.clear();
316 mCellularPermitted.clear();
317
318 // TODO: refine provisioning check to isTetherProvisioningRequired() ??
markchien3394e142019-04-09 15:53:24 +0800319 if (!config.hasMobileHotspotProvisionApp()
320 || carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
321 evaluateCellularPermission(config);
markchien3b519632018-09-07 16:19:12 +0800322 return;
markchienf2731272019-01-16 17:44:13 +0800323 }
324
markchien3b519632018-09-07 16:19:12 +0800325 if (mUsingCellularAsUpstream) {
markchien3394e142019-04-09 15:53:24 +0800326 handleMaybeRunProvisioning(config);
markchienb6eb2c22018-07-18 14:29:20 +0800327 }
328 }
329
markchien3394e142019-04-09 15:53:24 +0800330 /**
331 * Get carrier configuration bundle.
332 * @param config an object that encapsulates the various tethering configuration elements.
333 * */
334 public PersistableBundle getCarrierConfig(final TetheringConfiguration config) {
markchien29a650c2019-03-19 20:57:04 +0800335 final CarrierConfigManager configManager = (CarrierConfigManager) mContext
336 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
337 if (configManager == null) return null;
338
markchien3394e142019-04-09 15:53:24 +0800339 final PersistableBundle carrierConfig = configManager.getConfigForSubId(config.subId);
markchien29a650c2019-03-19 20:57:04 +0800340
341 if (CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) {
342 return carrierConfig;
343 }
344
345 return null;
346 }
347
markchienb6eb2c22018-07-18 14:29:20 +0800348 // The logic here is aimed solely at confirming that a CarrierConfig exists
349 // and affirms that entitlement checks are not required.
350 //
351 // TODO: find a better way to express this, or alter the checking process
352 // entirely so that this is more intuitive.
markchien3394e142019-04-09 15:53:24 +0800353 private boolean carrierConfigAffirmsEntitlementCheckNotRequired(
354 final TetheringConfiguration config) {
markchienb6eb2c22018-07-18 14:29:20 +0800355 // Check carrier config for entitlement checks
markchien3394e142019-04-09 15:53:24 +0800356 final PersistableBundle carrierConfig = getCarrierConfig(config);
markchienb6eb2c22018-07-18 14:29:20 +0800357 if (carrierConfig == null) return false;
358
359 // A CarrierConfigManager was found and it has a config.
360 final boolean isEntitlementCheckRequired = carrierConfig.getBoolean(
361 CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
362 return !isEntitlementCheckRequired;
363 }
364
markchien3b519632018-09-07 16:19:12 +0800365 /**
366 * Run no UI tethering provisioning check.
367 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
markchien3394e142019-04-09 15:53:24 +0800368 * @param subId default data subscription ID.
markchien3b519632018-09-07 16:19:12 +0800369 */
markchien3394e142019-04-09 15:53:24 +0800370 @VisibleForTesting
371 protected void runSilentTetherProvisioning(int type, int subId) {
markchien9f246bd2019-04-03 10:43:09 +0800372 if (DBG) mLog.i("runSilentTetherProvisioning: " + type);
markchien29b70142019-03-26 21:41:59 +0800373 // For silent provisioning, settings would stop tethering when entitlement fail.
markchien3394e142019-04-09 15:53:24 +0800374 ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null);
markchien3b519632018-09-07 16:19:12 +0800375
markchienb6eb2c22018-07-18 14:29:20 +0800376 Intent intent = new Intent();
377 intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
378 intent.putExtra(EXTRA_RUN_PROVISION, true);
379 intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
markchien3394e142019-04-09 15:53:24 +0800380 intent.putExtra(EXTRA_SUBID, subId);
markchienb6eb2c22018-07-18 14:29:20 +0800381 intent.setComponent(TETHER_SERVICE);
382 final long ident = Binder.clearCallingIdentity();
383 try {
384 mContext.startServiceAsUser(intent, UserHandle.CURRENT);
385 } finally {
386 Binder.restoreCallingIdentity(ident);
387 }
388 }
389
markchien3394e142019-04-09 15:53:24 +0800390 private void runUiTetherProvisioning(int type, int subId) {
391 ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null);
392 runUiTetherProvisioning(type, subId, receiver);
393 }
394
markchien3b519632018-09-07 16:19:12 +0800395 /**
396 * Run the UI-enabled tethering provisioning check.
397 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
markchien3394e142019-04-09 15:53:24 +0800398 * @param subId default data subscription ID.
399 * @param receiver to receive entitlement check result.
markchien3b519632018-09-07 16:19:12 +0800400 */
401 @VisibleForTesting
markchien3394e142019-04-09 15:53:24 +0800402 protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) {
markchien9f246bd2019-04-03 10:43:09 +0800403 if (DBG) mLog.i("runUiTetherProvisioning: " + type);
markchien3b519632018-09-07 16:19:12 +0800404
markchienb6eb2c22018-07-18 14:29:20 +0800405 Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
406 intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
407 intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
markchien3394e142019-04-09 15:53:24 +0800408 intent.putExtra(EXTRA_SUBID, subId);
markchienb6eb2c22018-07-18 14:29:20 +0800409 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
410 final long ident = Binder.clearCallingIdentity();
411 try {
412 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
413 } finally {
414 Binder.restoreCallingIdentity(ident);
415 }
416 }
417
markchien3b519632018-09-07 16:19:12 +0800418 // Not needed to check if this don't run on the handler thread because it's private.
markchien3394e142019-04-09 15:53:24 +0800419 private void scheduleProvisioningRechecks(final TetheringConfiguration config) {
markchien3b519632018-09-07 16:19:12 +0800420 if (mProvisioningRecheckAlarm == null) {
markchien3394e142019-04-09 15:53:24 +0800421 final int period = config.provisioningCheckPeriod;
markchien3b519632018-09-07 16:19:12 +0800422 if (period <= 0) return;
markchienb6eb2c22018-07-18 14:29:20 +0800423
markchien3b519632018-09-07 16:19:12 +0800424 Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
425 mProvisioningRecheckAlarm = PendingIntent.getBroadcast(mContext, 0, intent, 0);
426 AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
427 Context.ALARM_SERVICE);
428 long periodMs = period * MS_PER_HOUR;
429 long firstAlarmTime = SystemClock.elapsedRealtime() + periodMs;
430 alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstAlarmTime, periodMs,
431 mProvisioningRecheckAlarm);
markchienb6eb2c22018-07-18 14:29:20 +0800432 }
433 }
434
markchien3b519632018-09-07 16:19:12 +0800435 private void cancelTetherProvisioningRechecks() {
436 if (mProvisioningRecheckAlarm != null) {
437 AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
438 Context.ALARM_SERVICE);
439 alarmManager.cancel(mProvisioningRecheckAlarm);
440 mProvisioningRecheckAlarm = null;
441 }
442 }
443
markchien3394e142019-04-09 15:53:24 +0800444 private void evaluateCellularPermission(final TetheringConfiguration config) {
markchien3b519632018-09-07 16:19:12 +0800445 final boolean oldPermitted = mCellularUpstreamPermitted;
markchien3394e142019-04-09 15:53:24 +0800446 mCellularUpstreamPermitted = (!isTetherProvisioningRequired(config)
markchien3b519632018-09-07 16:19:12 +0800447 || mCellularPermitted.indexOfValue(TETHER_ERROR_NO_ERROR) > -1);
448
449 if (DBG) {
markchien9f246bd2019-04-03 10:43:09 +0800450 mLog.i("Cellular permission change from " + oldPermitted
markchien3b519632018-09-07 16:19:12 +0800451 + " to " + mCellularUpstreamPermitted);
452 }
453
454 if (mCellularUpstreamPermitted != oldPermitted) {
455 mLog.log("Cellular permission change: " + mCellularUpstreamPermitted);
456 mTetherMasterSM.sendMessage(mPermissionChangeMessageCode);
457 }
458 // Only schedule periodic re-check when tether is provisioned
459 // and the result is ok.
460 if (mCellularUpstreamPermitted && mCellularPermitted.size() > 0) {
markchien3394e142019-04-09 15:53:24 +0800461 scheduleProvisioningRechecks(config);
markchien3b519632018-09-07 16:19:12 +0800462 } else {
463 cancelTetherProvisioningRechecks();
464 }
465 }
466
467 /**
468 * Add the mapping between provisioning result and tethering type.
469 * Notify UpstreamNetworkMonitor if Cellular permission changes.
470 *
471 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
472 * @param resultCode Provisioning result
473 */
474 protected void addDownstreamMapping(int type, int resultCode) {
markchien9f246bd2019-04-03 10:43:09 +0800475 mLog.i("addDownstreamMapping: " + type + ", result: " + resultCode
476 + " ,TetherTypeRequested: " + mCurrentTethers.contains(type));
markchien3b519632018-09-07 16:19:12 +0800477 if (!mCurrentTethers.contains(type)) return;
478
479 mCellularPermitted.put(type, resultCode);
markchien3394e142019-04-09 15:53:24 +0800480 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
481 evaluateCellularPermission(config);
markchien3b519632018-09-07 16:19:12 +0800482 }
483
484 /**
485 * Remove the mapping for input tethering type.
486 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
487 */
488 protected void removeDownstreamMapping(int type) {
markchien9f246bd2019-04-03 10:43:09 +0800489 mLog.i("removeDownstreamMapping: " + type);
markchien3b519632018-09-07 16:19:12 +0800490 mCellularPermitted.delete(type);
markchien3394e142019-04-09 15:53:24 +0800491 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
492 evaluateCellularPermission(config);
markchien3b519632018-09-07 16:19:12 +0800493 }
494
495 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
496 @Override
497 public void onReceive(Context context, Intent intent) {
498 if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) {
499 mLog.log("Received provisioning alarm");
markchien3394e142019-04-09 15:53:24 +0800500 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
501 reevaluateSimCardProvisioning(config);
markchien3b519632018-09-07 16:19:12 +0800502 }
503 }
504 };
505
506 private class EntitlementHandler extends Handler {
507 EntitlementHandler(Looper looper) {
508 super(looper);
509 }
510
511 @Override
512 public void handleMessage(Message msg) {
513 switch (msg.what) {
514 case EVENT_START_PROVISIONING:
515 handleStartProvisioningIfNeeded(msg.arg1, toBool(msg.arg2));
516 break;
517 case EVENT_STOP_PROVISIONING:
518 handleStopProvisioningIfNeeded(msg.arg1);
519 break;
520 case EVENT_UPSTREAM_CHANGED:
521 handleNotifyUpstream(toBool(msg.arg1));
522 break;
523 case EVENT_MAYBE_RUN_PROVISIONING:
markchien3394e142019-04-09 15:53:24 +0800524 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
525 handleMaybeRunProvisioning(config);
markchien3b519632018-09-07 16:19:12 +0800526 break;
527 case EVENT_GET_ENTITLEMENT_VALUE:
markchien0df2ebc42019-09-30 14:40:57 +0800528 handleRequestLatestTetheringEntitlementValue(msg.arg1,
529 (ResultReceiver) msg.obj, toBool(msg.arg2));
markchien3b519632018-09-07 16:19:12 +0800530 break;
531 default:
532 mLog.log("Unknown event: " + msg.what);
533 break;
534 }
535 }
536 }
537
538 private static boolean toBool(int encodedBoolean) {
539 return encodedBoolean != 0;
540 }
541
542 private static int encodeBool(boolean b) {
543 return b ? 1 : 0;
544 }
545
546 private static boolean isValidDownstreamType(int type) {
547 switch (type) {
548 case TETHERING_BLUETOOTH:
549 case TETHERING_USB:
550 case TETHERING_WIFI:
551 return true;
552 default:
553 return false;
554 }
555 }
556
557 /**
558 * Dump the infromation of EntitlementManager.
559 * @param pw {@link PrintWriter} is used to print formatted
560 */
561 public void dump(PrintWriter pw) {
562 pw.print("mCellularUpstreamPermitted: ");
563 pw.println(mCellularUpstreamPermitted);
564 for (Integer type : mCurrentTethers) {
565 pw.print("Type: ");
566 pw.print(typeString(type));
567 if (mCellularPermitted.indexOfKey(type) > -1) {
568 pw.print(", Value: ");
569 pw.println(errorString(mCellularPermitted.get(type)));
570 } else {
571 pw.println(", Value: empty");
572 }
573 }
574 }
575
576 private static String typeString(int type) {
577 switch (type) {
578 case TETHERING_BLUETOOTH: return "TETHERING_BLUETOOTH";
579 case TETHERING_INVALID: return "TETHERING_INVALID";
580 case TETHERING_USB: return "TETHERING_USB";
581 case TETHERING_WIFI: return "TETHERING_WIFI";
582 default:
583 return String.format("TETHERING UNKNOWN TYPE (%d)", type);
584 }
585 }
586
587 private static String errorString(int value) {
588 switch (value) {
589 case TETHER_ERROR_ENTITLEMENT_UNKONWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
590 case TETHER_ERROR_NO_ERROR: return "TETHER_ERROR_NO_ERROR";
591 case TETHER_ERROR_PROVISION_FAILED: return "TETHER_ERROR_PROVISION_FAILED";
592 default:
593 return String.format("UNKNOWN ERROR (%d)", value);
markchienb6eb2c22018-07-18 14:29:20 +0800594 }
595 }
markchienf2731272019-01-16 17:44:13 +0800596
markchien29b70142019-03-26 21:41:59 +0800597 private ResultReceiver buildProxyReceiver(int type, boolean notifyFail,
598 final ResultReceiver receiver) {
markchien3b519632018-09-07 16:19:12 +0800599 ResultReceiver rr = new ResultReceiver(mHandler) {
markchienf2731272019-01-16 17:44:13 +0800600 @Override
601 protected void onReceiveResult(int resultCode, Bundle resultData) {
602 int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
markchien3b519632018-09-07 16:19:12 +0800603 addDownstreamMapping(type, updatedCacheValue);
markchien29b70142019-03-26 21:41:59 +0800604 if (updatedCacheValue == TETHER_ERROR_PROVISION_FAILED && notifyFail) {
605 mListener.onUiEntitlementFailed(type);
606 }
markchien3b519632018-09-07 16:19:12 +0800607 if (receiver != null) receiver.send(updatedCacheValue, null);
markchienf2731272019-01-16 17:44:13 +0800608 }
609 };
610
611 return writeToParcel(rr);
612 }
613
markchien3b519632018-09-07 16:19:12 +0800614 // Instances of ResultReceiver need to be public classes for remote processes to be able
615 // to load them (otherwise, ClassNotFoundException). For private classes, this method
616 // performs a trick : round-trip parceling any instance of ResultReceiver will return a
617 // vanilla instance of ResultReceiver sharing the binder token with the original receiver.
618 // The binder token has a reference to the original instance of the private class and will
619 // still call its methods, and can be sent over. However it cannot be used for anything
620 // else than sending over a Binder call.
621 // While round-trip parceling is not great, there is currently no other way of generating
622 // a vanilla instance of ResultReceiver because all its fields are private.
markchienf2731272019-01-16 17:44:13 +0800623 private ResultReceiver writeToParcel(final ResultReceiver receiver) {
markchienf2731272019-01-16 17:44:13 +0800624 Parcel parcel = Parcel.obtain();
625 receiver.writeToParcel(parcel, 0);
626 parcel.setDataPosition(0);
627 ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
628 parcel.recycle();
629 return receiverForSending;
630 }
631
632 /**
633 * Update the last entitlement value to internal cache
634 *
635 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
636 * @param resultCode last entitlement value
637 * @return the last updated entitlement value
638 */
markchien3b519632018-09-07 16:19:12 +0800639 private int updateEntitlementCacheValue(int type, int resultCode) {
markchienf2731272019-01-16 17:44:13 +0800640 if (DBG) {
markchien9f246bd2019-04-03 10:43:09 +0800641 mLog.i("updateEntitlementCacheValue: " + type + ", result: " + resultCode);
markchienf2731272019-01-16 17:44:13 +0800642 }
markchien3b519632018-09-07 16:19:12 +0800643 if (resultCode == TETHER_ERROR_NO_ERROR) {
644 mEntitlementCacheValue.put(type, resultCode);
645 return resultCode;
646 } else {
647 mEntitlementCacheValue.put(type, TETHER_ERROR_PROVISION_FAILED);
648 return TETHER_ERROR_PROVISION_FAILED;
markchienf2731272019-01-16 17:44:13 +0800649 }
650 }
651
652 /** Get the last value of the tethering entitlement check. */
markchien0df2ebc42019-09-30 14:40:57 +0800653 public void requestLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver,
markchienf2731272019-01-16 17:44:13 +0800654 boolean showEntitlementUi) {
markchien3b519632018-09-07 16:19:12 +0800655 mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ENTITLEMENT_VALUE,
656 downstream, encodeBool(showEntitlementUi), receiver));
657
658 }
659
markchien0df2ebc42019-09-30 14:40:57 +0800660 private void handleRequestLatestTetheringEntitlementValue(int downstream,
661 ResultReceiver receiver, boolean showEntitlementUi) {
markchien3394e142019-04-09 15:53:24 +0800662 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
663 if (!isTetherProvisioningRequired(config)) {
markchienf2731272019-01-16 17:44:13 +0800664 receiver.send(TETHER_ERROR_NO_ERROR, null);
665 return;
666 }
667
markchien3b519632018-09-07 16:19:12 +0800668 final int cacheValue = mEntitlementCacheValue.get(
markchienf2731272019-01-16 17:44:13 +0800669 downstream, TETHER_ERROR_ENTITLEMENT_UNKONWN);
markchienf2731272019-01-16 17:44:13 +0800670 if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
671 receiver.send(cacheValue, null);
672 } else {
markchien29b70142019-03-26 21:41:59 +0800673 ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
markchien3394e142019-04-09 15:53:24 +0800674 runUiTetherProvisioning(downstream, config.subId, proxy);
markchienf2731272019-01-16 17:44:13 +0800675 }
676 }
markchienb6eb2c22018-07-18 14:29:20 +0800677}