blob: 6b0f1de7ce85966ab4da2cc4ec6b64157eadb0b5 [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;
markchienb6eb2c22018-07-18 14:29:20 +080050import android.os.UserHandle;
51import android.provider.Settings;
52import android.telephony.CarrierConfigManager;
53import android.util.ArraySet;
markchienf2731272019-01-16 17:44:13 +080054import android.util.SparseIntArray;
markchienb6eb2c22018-07-18 14:29:20 +080055
markchienb6eb2c22018-07-18 14:29:20 +080056import com.android.internal.annotations.VisibleForTesting;
markchienf2731272019-01-16 17:44:13 +080057import com.android.internal.util.StateMachine;
markchienb6eb2c22018-07-18 14:29:20 +080058import com.android.server.connectivity.MockableSystemProperties;
59
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 MockableSystemProperties mSystemProperties;
98 private final SharedLog mLog;
markchienf2731272019-01-16 17:44:13 +080099 private final SparseIntArray mEntitlementCacheValue;
markchien3b519632018-09-07 16:19:12 +0800100 private final EntitlementHandler mHandler;
markchien3b519632018-09-07 16:19:12 +0800101 private final StateMachine mTetherMasterSM;
102 // Key: ConnectivityManager.TETHERING_*(downstream).
103 // Value: ConnectivityManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
104 private final SparseIntArray mCellularPermitted;
105 private PendingIntent mProvisioningRecheckAlarm;
106 private boolean mCellularUpstreamPermitted = true;
107 private boolean mUsingCellularAsUpstream = false;
108 private boolean mNeedReRunProvisioningUi = false;
markchien29b70142019-03-26 21:41:59 +0800109 private OnUiEntitlementFailedListener mListener;
markchien3394e142019-04-09 15:53:24 +0800110 private TetheringConfigurationFetcher mFetcher;
markchienb6eb2c22018-07-18 14:29:20 +0800111
markchienf2731272019-01-16 17:44:13 +0800112 public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
markchien3b519632018-09-07 16:19:12 +0800113 int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
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();
markchienb6eb2c22018-07-18 14:29:20 +0800118 mSystemProperties = systemProperties;
markchienf2731272019-01-16 17:44:13 +0800119 mEntitlementCacheValue = new SparseIntArray();
markchien3b519632018-09-07 16:19:12 +0800120 mTetherMasterSM = tetherMasterSM;
121 mPermissionChangeMessageCode = permissionChangeMessageCode;
122 final Handler masterHandler = tetherMasterSM.getHandler();
123 // Create entitlement's own handler which is associated with TetherMaster thread
124 // let all entitlement processes run in the same thread.
125 mHandler = new EntitlementHandler(masterHandler.getLooper());
126 mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM),
127 null, mHandler);
markchienb6eb2c22018-07-18 14:29:20 +0800128 }
129
markchien29b70142019-03-26 21:41:59 +0800130 public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
131 mListener = listener;
132 }
133
134 /** Callback fired when UI entitlement failed. */
135 public interface OnUiEntitlementFailedListener {
136 /**
137 * Ui entitlement check fails in |downstream|.
138 *
markchienf303c5a2019-09-23 20:29:54 +0800139 * @param downstream tethering type from ConnectivityManager.TETHERING_{@code *}.
markchien29b70142019-03-26 21:41:59 +0800140 */
141 void onUiEntitlementFailed(int downstream);
142 }
143
markchien3394e142019-04-09 15:53:24 +0800144 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 */
155 TetheringConfiguration fetchTetheringConfiguration();
markchienb6eb2c22018-07-18 14:29:20 +0800156 }
157
158 /**
markchien3b519632018-09-07 16:19:12 +0800159 * Check if cellular upstream is permitted.
markchienb6eb2c22018-07-18 14:29:20 +0800160 */
markchien3b519632018-09-07 16:19:12 +0800161 public boolean isCellularUpstreamPermitted() {
markchien426311b2019-08-09 21:43:38 +0800162 // If provisioning is required and EntitlementManager don't know any downstream,
163 // cellular upstream should not be allowed.
164 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
165 if (mCurrentTethers.size() == 0 && isTetherProvisioningRequired(config)) {
166 return false;
167 }
markchien3b519632018-09-07 16:19:12 +0800168 return mCellularUpstreamPermitted;
169 }
170
171 /**
172 * This is called when tethering starts.
173 * Launch provisioning app if upstream is cellular.
174 *
175 * @param downstreamType tethering type from ConnectivityManager.TETHERING_{@code *}
176 * @param showProvisioningUi a boolean indicating whether to show the
177 * provisioning app UI if there is one.
178 */
179 public void startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi) {
180 mHandler.sendMessage(mHandler.obtainMessage(EVENT_START_PROVISIONING,
181 downstreamType, encodeBool(showProvisioningUi)));
182 }
183
184 private void handleStartProvisioningIfNeeded(int type, boolean showProvisioningUi) {
185 if (!isValidDownstreamType(type)) return;
186
187 if (!mCurrentTethers.contains(type)) mCurrentTethers.add(type);
188
markchien3394e142019-04-09 15:53:24 +0800189 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
190 if (isTetherProvisioningRequired(config)) {
markchien3b519632018-09-07 16:19:12 +0800191 // If provisioning is required and the result is not available yet,
192 // cellular upstream should not be allowed.
193 if (mCellularPermitted.size() == 0) {
194 mCellularUpstreamPermitted = false;
195 }
196 // If upstream is not cellular, provisioning app would not be launched
197 // till upstream change to cellular.
198 if (mUsingCellularAsUpstream) {
199 if (showProvisioningUi) {
markchien3394e142019-04-09 15:53:24 +0800200 runUiTetherProvisioning(type, config.subId);
markchien3b519632018-09-07 16:19:12 +0800201 } else {
markchien3394e142019-04-09 15:53:24 +0800202 runSilentTetherProvisioning(type, config.subId);
markchien3b519632018-09-07 16:19:12 +0800203 }
204 mNeedReRunProvisioningUi = false;
205 } else {
206 mNeedReRunProvisioningUi |= showProvisioningUi;
207 }
208 } else {
209 mCellularUpstreamPermitted = true;
markchienb6eb2c22018-07-18 14:29:20 +0800210 }
211 }
212
213 /**
214 * Tell EntitlementManager that a given type of tethering has been disabled
215 *
markchien3b519632018-09-07 16:19:12 +0800216 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
markchienb6eb2c22018-07-18 14:29:20 +0800217 */
markchien3b519632018-09-07 16:19:12 +0800218 public void stopProvisioningIfNeeded(int type) {
219 mHandler.sendMessage(mHandler.obtainMessage(EVENT_STOP_PROVISIONING, type, 0));
220 }
221
222 private void handleStopProvisioningIfNeeded(int type) {
223 if (!isValidDownstreamType(type)) return;
224
225 mCurrentTethers.remove(type);
226 // There are lurking bugs where the notion of "provisioning required" or
227 // "tethering supported" may change without without tethering being notified properly.
228 // Remove the mapping all the time no matter provisioning is required or not.
229 removeDownstreamMapping(type);
230 }
231
232 /**
233 * Notify EntitlementManager if upstream is cellular or not.
234 *
235 * @param isCellular whether tethering upstream is cellular.
236 */
237 public void notifyUpstream(boolean isCellular) {
238 mHandler.sendMessage(mHandler.obtainMessage(
239 EVENT_UPSTREAM_CHANGED, encodeBool(isCellular), 0));
240 }
241
242 private void handleNotifyUpstream(boolean isCellular) {
243 if (DBG) {
markchien9f246bd2019-04-03 10:43:09 +0800244 mLog.i("notifyUpstream: " + isCellular
markchien3b519632018-09-07 16:19:12 +0800245 + ", mCellularUpstreamPermitted: " + mCellularUpstreamPermitted
246 + ", mNeedReRunProvisioningUi: " + mNeedReRunProvisioningUi);
247 }
248 mUsingCellularAsUpstream = isCellular;
249
250 if (mUsingCellularAsUpstream) {
markchien3394e142019-04-09 15:53:24 +0800251 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
252 handleMaybeRunProvisioning(config);
markchien3b519632018-09-07 16:19:12 +0800253 }
254 }
255
256 /** Run provisioning if needed */
257 public void maybeRunProvisioning() {
258 mHandler.sendMessage(mHandler.obtainMessage(EVENT_MAYBE_RUN_PROVISIONING));
259 }
260
markchien3394e142019-04-09 15:53:24 +0800261 private void handleMaybeRunProvisioning(final TetheringConfiguration config) {
262 if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired(config)) {
markchien3b519632018-09-07 16:19:12 +0800263 return;
264 }
265
266 // Whenever any entitlement value changes, all downstreams will re-evaluate whether they
267 // are allowed. Therefore even if the silent check here ends in a failure and the UI later
268 // yields success, then the downstream that got a failure will re-evaluate as a result of
269 // the change and get the new correct value.
270 for (Integer downstream : mCurrentTethers) {
271 if (mCellularPermitted.indexOfKey(downstream) < 0) {
272 if (mNeedReRunProvisioningUi) {
273 mNeedReRunProvisioningUi = false;
markchien3394e142019-04-09 15:53:24 +0800274 runUiTetherProvisioning(downstream, config.subId);
markchien3b519632018-09-07 16:19:12 +0800275 } else {
markchien3394e142019-04-09 15:53:24 +0800276 runSilentTetherProvisioning(downstream, config.subId);
markchien3b519632018-09-07 16:19:12 +0800277 }
278 }
markchienb6eb2c22018-07-18 14:29:20 +0800279 }
280 }
281
282 /**
283 * Check if the device requires a provisioning check in order to enable tethering.
284 *
markchien3394e142019-04-09 15:53:24 +0800285 * @param config an object that encapsulates the various tethering configuration elements.
markchienb6eb2c22018-07-18 14:29:20 +0800286 * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
287 */
288 @VisibleForTesting
markchien3394e142019-04-09 15:53:24 +0800289 protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) {
markchienb6eb2c22018-07-18 14:29:20 +0800290 if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
markchien3394e142019-04-09 15:53:24 +0800291 || config.provisioningApp.length == 0) {
markchienb6eb2c22018-07-18 14:29:20 +0800292 return false;
293 }
markchien3394e142019-04-09 15:53:24 +0800294 if (carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
markchienb6eb2c22018-07-18 14:29:20 +0800295 return false;
296 }
markchien3394e142019-04-09 15:53:24 +0800297 return (config.provisioningApp.length == 2);
markchienb6eb2c22018-07-18 14:29:20 +0800298 }
299
300 /**
markchien3b519632018-09-07 16:19:12 +0800301 * Re-check tethering provisioning for all enabled tether types.
markchienb6eb2c22018-07-18 14:29:20 +0800302 * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
markchien3b519632018-09-07 16:19:12 +0800303 *
markchien3394e142019-04-09 15:53:24 +0800304 * @param config an object that encapsulates the various tethering configuration elements.
markchien3b519632018-09-07 16:19:12 +0800305 * Note: this method is only called from TetherMaster on the handler thread.
306 * If there are new callers from different threads, the logic should move to
307 * masterHandler to avoid race conditions.
markchienb6eb2c22018-07-18 14:29:20 +0800308 */
markchien3394e142019-04-09 15:53:24 +0800309 public void reevaluateSimCardProvisioning(final TetheringConfiguration config) {
markchien9f246bd2019-04-03 10:43:09 +0800310 if (DBG) mLog.i("reevaluateSimCardProvisioning");
markchien3b519632018-09-07 16:19:12 +0800311
312 if (!mHandler.getLooper().isCurrentThread()) {
313 // Except for test, this log should not appear in normal flow.
314 mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread");
315 }
316 mEntitlementCacheValue.clear();
317 mCellularPermitted.clear();
318
319 // TODO: refine provisioning check to isTetherProvisioningRequired() ??
markchien3394e142019-04-09 15:53:24 +0800320 if (!config.hasMobileHotspotProvisionApp()
321 || carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
322 evaluateCellularPermission(config);
markchien3b519632018-09-07 16:19:12 +0800323 return;
markchienf2731272019-01-16 17:44:13 +0800324 }
325
markchien3b519632018-09-07 16:19:12 +0800326 if (mUsingCellularAsUpstream) {
markchien3394e142019-04-09 15:53:24 +0800327 handleMaybeRunProvisioning(config);
markchienb6eb2c22018-07-18 14:29:20 +0800328 }
329 }
330
markchien3394e142019-04-09 15:53:24 +0800331 /**
332 * Get carrier configuration bundle.
333 * @param config an object that encapsulates the various tethering configuration elements.
334 * */
335 public PersistableBundle getCarrierConfig(final TetheringConfiguration config) {
markchien29a650c2019-03-19 20:57:04 +0800336 final CarrierConfigManager configManager = (CarrierConfigManager) mContext
337 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
338 if (configManager == null) return null;
339
markchien3394e142019-04-09 15:53:24 +0800340 final PersistableBundle carrierConfig = configManager.getConfigForSubId(config.subId);
markchien29a650c2019-03-19 20:57:04 +0800341
342 if (CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) {
343 return carrierConfig;
344 }
345
346 return null;
347 }
348
markchienb6eb2c22018-07-18 14:29:20 +0800349 // The logic here is aimed solely at confirming that a CarrierConfig exists
350 // and affirms that entitlement checks are not required.
351 //
352 // TODO: find a better way to express this, or alter the checking process
353 // entirely so that this is more intuitive.
markchien3394e142019-04-09 15:53:24 +0800354 private boolean carrierConfigAffirmsEntitlementCheckNotRequired(
355 final TetheringConfiguration config) {
markchienb6eb2c22018-07-18 14:29:20 +0800356 // Check carrier config for entitlement checks
markchien3394e142019-04-09 15:53:24 +0800357 final PersistableBundle carrierConfig = getCarrierConfig(config);
markchienb6eb2c22018-07-18 14:29:20 +0800358 if (carrierConfig == null) return false;
359
360 // A CarrierConfigManager was found and it has a config.
361 final boolean isEntitlementCheckRequired = carrierConfig.getBoolean(
362 CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
363 return !isEntitlementCheckRequired;
364 }
365
markchien3b519632018-09-07 16:19:12 +0800366 /**
367 * Run no UI tethering provisioning check.
368 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
markchien3394e142019-04-09 15:53:24 +0800369 * @param subId default data subscription ID.
markchien3b519632018-09-07 16:19:12 +0800370 */
markchien3394e142019-04-09 15:53:24 +0800371 @VisibleForTesting
372 protected void runSilentTetherProvisioning(int type, int subId) {
markchien9f246bd2019-04-03 10:43:09 +0800373 if (DBG) mLog.i("runSilentTetherProvisioning: " + type);
markchien29b70142019-03-26 21:41:59 +0800374 // For silent provisioning, settings would stop tethering when entitlement fail.
markchien3394e142019-04-09 15:53:24 +0800375 ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null);
markchien3b519632018-09-07 16:19:12 +0800376
markchienb6eb2c22018-07-18 14:29:20 +0800377 Intent intent = new Intent();
378 intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
379 intent.putExtra(EXTRA_RUN_PROVISION, true);
380 intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
markchien3394e142019-04-09 15:53:24 +0800381 intent.putExtra(EXTRA_SUBID, subId);
markchienb6eb2c22018-07-18 14:29:20 +0800382 intent.setComponent(TETHER_SERVICE);
383 final long ident = Binder.clearCallingIdentity();
384 try {
385 mContext.startServiceAsUser(intent, UserHandle.CURRENT);
386 } finally {
387 Binder.restoreCallingIdentity(ident);
388 }
389 }
390
markchien3394e142019-04-09 15:53:24 +0800391 private void runUiTetherProvisioning(int type, int subId) {
392 ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null);
393 runUiTetherProvisioning(type, subId, receiver);
394 }
395
markchien3b519632018-09-07 16:19:12 +0800396 /**
397 * Run the UI-enabled tethering provisioning check.
398 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
markchien3394e142019-04-09 15:53:24 +0800399 * @param subId default data subscription ID.
400 * @param receiver to receive entitlement check result.
markchien3b519632018-09-07 16:19:12 +0800401 */
402 @VisibleForTesting
markchien3394e142019-04-09 15:53:24 +0800403 protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) {
markchien9f246bd2019-04-03 10:43:09 +0800404 if (DBG) mLog.i("runUiTetherProvisioning: " + type);
markchien3b519632018-09-07 16:19:12 +0800405
markchienb6eb2c22018-07-18 14:29:20 +0800406 Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
407 intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
408 intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
markchien3394e142019-04-09 15:53:24 +0800409 intent.putExtra(EXTRA_SUBID, subId);
markchienb6eb2c22018-07-18 14:29:20 +0800410 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
411 final long ident = Binder.clearCallingIdentity();
412 try {
413 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
414 } finally {
415 Binder.restoreCallingIdentity(ident);
416 }
417 }
418
markchien3b519632018-09-07 16:19:12 +0800419 // Not needed to check if this don't run on the handler thread because it's private.
markchien3394e142019-04-09 15:53:24 +0800420 private void scheduleProvisioningRechecks(final TetheringConfiguration config) {
markchien3b519632018-09-07 16:19:12 +0800421 if (mProvisioningRecheckAlarm == null) {
markchien3394e142019-04-09 15:53:24 +0800422 final int period = config.provisioningCheckPeriod;
markchien3b519632018-09-07 16:19:12 +0800423 if (period <= 0) return;
markchienb6eb2c22018-07-18 14:29:20 +0800424
markchien3b519632018-09-07 16:19:12 +0800425 Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
426 mProvisioningRecheckAlarm = PendingIntent.getBroadcast(mContext, 0, intent, 0);
427 AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
428 Context.ALARM_SERVICE);
429 long periodMs = period * MS_PER_HOUR;
430 long firstAlarmTime = SystemClock.elapsedRealtime() + periodMs;
431 alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstAlarmTime, periodMs,
432 mProvisioningRecheckAlarm);
markchienb6eb2c22018-07-18 14:29:20 +0800433 }
434 }
435
markchien3b519632018-09-07 16:19:12 +0800436 private void cancelTetherProvisioningRechecks() {
437 if (mProvisioningRecheckAlarm != null) {
438 AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
439 Context.ALARM_SERVICE);
440 alarmManager.cancel(mProvisioningRecheckAlarm);
441 mProvisioningRecheckAlarm = null;
442 }
443 }
444
markchien3394e142019-04-09 15:53:24 +0800445 private void evaluateCellularPermission(final TetheringConfiguration config) {
markchien3b519632018-09-07 16:19:12 +0800446 final boolean oldPermitted = mCellularUpstreamPermitted;
markchien3394e142019-04-09 15:53:24 +0800447 mCellularUpstreamPermitted = (!isTetherProvisioningRequired(config)
markchien3b519632018-09-07 16:19:12 +0800448 || mCellularPermitted.indexOfValue(TETHER_ERROR_NO_ERROR) > -1);
449
450 if (DBG) {
markchien9f246bd2019-04-03 10:43:09 +0800451 mLog.i("Cellular permission change from " + oldPermitted
markchien3b519632018-09-07 16:19:12 +0800452 + " to " + mCellularUpstreamPermitted);
453 }
454
455 if (mCellularUpstreamPermitted != oldPermitted) {
456 mLog.log("Cellular permission change: " + mCellularUpstreamPermitted);
457 mTetherMasterSM.sendMessage(mPermissionChangeMessageCode);
458 }
459 // Only schedule periodic re-check when tether is provisioned
460 // and the result is ok.
461 if (mCellularUpstreamPermitted && mCellularPermitted.size() > 0) {
markchien3394e142019-04-09 15:53:24 +0800462 scheduleProvisioningRechecks(config);
markchien3b519632018-09-07 16:19:12 +0800463 } else {
464 cancelTetherProvisioningRechecks();
465 }
466 }
467
468 /**
469 * Add the mapping between provisioning result and tethering type.
470 * Notify UpstreamNetworkMonitor if Cellular permission changes.
471 *
472 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
473 * @param resultCode Provisioning result
474 */
475 protected void addDownstreamMapping(int type, int resultCode) {
markchien9f246bd2019-04-03 10:43:09 +0800476 mLog.i("addDownstreamMapping: " + type + ", result: " + resultCode
477 + " ,TetherTypeRequested: " + mCurrentTethers.contains(type));
markchien3b519632018-09-07 16:19:12 +0800478 if (!mCurrentTethers.contains(type)) return;
479
480 mCellularPermitted.put(type, resultCode);
markchien3394e142019-04-09 15:53:24 +0800481 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
482 evaluateCellularPermission(config);
markchien3b519632018-09-07 16:19:12 +0800483 }
484
485 /**
486 * Remove the mapping for input tethering type.
487 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
488 */
489 protected void removeDownstreamMapping(int type) {
markchien9f246bd2019-04-03 10:43:09 +0800490 mLog.i("removeDownstreamMapping: " + type);
markchien3b519632018-09-07 16:19:12 +0800491 mCellularPermitted.delete(type);
markchien3394e142019-04-09 15:53:24 +0800492 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
493 evaluateCellularPermission(config);
markchien3b519632018-09-07 16:19:12 +0800494 }
495
496 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
497 @Override
498 public void onReceive(Context context, Intent intent) {
499 if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) {
500 mLog.log("Received provisioning alarm");
markchien3394e142019-04-09 15:53:24 +0800501 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
502 reevaluateSimCardProvisioning(config);
markchien3b519632018-09-07 16:19:12 +0800503 }
504 }
505 };
506
507 private class EntitlementHandler extends Handler {
508 EntitlementHandler(Looper looper) {
509 super(looper);
510 }
511
512 @Override
513 public void handleMessage(Message msg) {
514 switch (msg.what) {
515 case EVENT_START_PROVISIONING:
516 handleStartProvisioningIfNeeded(msg.arg1, toBool(msg.arg2));
517 break;
518 case EVENT_STOP_PROVISIONING:
519 handleStopProvisioningIfNeeded(msg.arg1);
520 break;
521 case EVENT_UPSTREAM_CHANGED:
522 handleNotifyUpstream(toBool(msg.arg1));
523 break;
524 case EVENT_MAYBE_RUN_PROVISIONING:
markchien3394e142019-04-09 15:53:24 +0800525 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
526 handleMaybeRunProvisioning(config);
markchien3b519632018-09-07 16:19:12 +0800527 break;
528 case EVENT_GET_ENTITLEMENT_VALUE:
529 handleGetLatestTetheringEntitlementValue(msg.arg1, (ResultReceiver) msg.obj,
530 toBool(msg.arg2));
531 break;
532 default:
533 mLog.log("Unknown event: " + msg.what);
534 break;
535 }
536 }
537 }
538
539 private static boolean toBool(int encodedBoolean) {
540 return encodedBoolean != 0;
541 }
542
543 private static int encodeBool(boolean b) {
544 return b ? 1 : 0;
545 }
546
547 private static boolean isValidDownstreamType(int type) {
548 switch (type) {
549 case TETHERING_BLUETOOTH:
550 case TETHERING_USB:
551 case TETHERING_WIFI:
552 return true;
553 default:
554 return false;
555 }
556 }
557
558 /**
559 * Dump the infromation of EntitlementManager.
560 * @param pw {@link PrintWriter} is used to print formatted
561 */
562 public void dump(PrintWriter pw) {
563 pw.print("mCellularUpstreamPermitted: ");
564 pw.println(mCellularUpstreamPermitted);
565 for (Integer type : mCurrentTethers) {
566 pw.print("Type: ");
567 pw.print(typeString(type));
568 if (mCellularPermitted.indexOfKey(type) > -1) {
569 pw.print(", Value: ");
570 pw.println(errorString(mCellularPermitted.get(type)));
571 } else {
572 pw.println(", Value: empty");
573 }
574 }
575 }
576
577 private static String typeString(int type) {
578 switch (type) {
579 case TETHERING_BLUETOOTH: return "TETHERING_BLUETOOTH";
580 case TETHERING_INVALID: return "TETHERING_INVALID";
581 case TETHERING_USB: return "TETHERING_USB";
582 case TETHERING_WIFI: return "TETHERING_WIFI";
583 default:
584 return String.format("TETHERING UNKNOWN TYPE (%d)", type);
585 }
586 }
587
588 private static String errorString(int value) {
589 switch (value) {
590 case TETHER_ERROR_ENTITLEMENT_UNKONWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
591 case TETHER_ERROR_NO_ERROR: return "TETHER_ERROR_NO_ERROR";
592 case TETHER_ERROR_PROVISION_FAILED: return "TETHER_ERROR_PROVISION_FAILED";
593 default:
594 return String.format("UNKNOWN ERROR (%d)", value);
markchienb6eb2c22018-07-18 14:29:20 +0800595 }
596 }
markchienf2731272019-01-16 17:44:13 +0800597
markchien29b70142019-03-26 21:41:59 +0800598 private ResultReceiver buildProxyReceiver(int type, boolean notifyFail,
599 final ResultReceiver receiver) {
markchien3b519632018-09-07 16:19:12 +0800600 ResultReceiver rr = new ResultReceiver(mHandler) {
markchienf2731272019-01-16 17:44:13 +0800601 @Override
602 protected void onReceiveResult(int resultCode, Bundle resultData) {
603 int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
markchien3b519632018-09-07 16:19:12 +0800604 addDownstreamMapping(type, updatedCacheValue);
markchien29b70142019-03-26 21:41:59 +0800605 if (updatedCacheValue == TETHER_ERROR_PROVISION_FAILED && notifyFail) {
606 mListener.onUiEntitlementFailed(type);
607 }
markchien3b519632018-09-07 16:19:12 +0800608 if (receiver != null) receiver.send(updatedCacheValue, null);
markchienf2731272019-01-16 17:44:13 +0800609 }
610 };
611
612 return writeToParcel(rr);
613 }
614
markchien3b519632018-09-07 16:19:12 +0800615 // Instances of ResultReceiver need to be public classes for remote processes to be able
616 // to load them (otherwise, ClassNotFoundException). For private classes, this method
617 // performs a trick : round-trip parceling any instance of ResultReceiver will return a
618 // vanilla instance of ResultReceiver sharing the binder token with the original receiver.
619 // The binder token has a reference to the original instance of the private class and will
620 // still call its methods, and can be sent over. However it cannot be used for anything
621 // else than sending over a Binder call.
622 // While round-trip parceling is not great, there is currently no other way of generating
623 // a vanilla instance of ResultReceiver because all its fields are private.
markchienf2731272019-01-16 17:44:13 +0800624 private ResultReceiver writeToParcel(final ResultReceiver receiver) {
markchienf2731272019-01-16 17:44:13 +0800625 Parcel parcel = Parcel.obtain();
626 receiver.writeToParcel(parcel, 0);
627 parcel.setDataPosition(0);
628 ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
629 parcel.recycle();
630 return receiverForSending;
631 }
632
633 /**
634 * Update the last entitlement value to internal cache
635 *
636 * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
637 * @param resultCode last entitlement value
638 * @return the last updated entitlement value
639 */
markchien3b519632018-09-07 16:19:12 +0800640 private int updateEntitlementCacheValue(int type, int resultCode) {
markchienf2731272019-01-16 17:44:13 +0800641 if (DBG) {
markchien9f246bd2019-04-03 10:43:09 +0800642 mLog.i("updateEntitlementCacheValue: " + type + ", result: " + resultCode);
markchienf2731272019-01-16 17:44:13 +0800643 }
markchien3b519632018-09-07 16:19:12 +0800644 if (resultCode == TETHER_ERROR_NO_ERROR) {
645 mEntitlementCacheValue.put(type, resultCode);
646 return resultCode;
647 } else {
648 mEntitlementCacheValue.put(type, TETHER_ERROR_PROVISION_FAILED);
649 return TETHER_ERROR_PROVISION_FAILED;
markchienf2731272019-01-16 17:44:13 +0800650 }
651 }
652
653 /** Get the last value of the tethering entitlement check. */
markchien9554abf2019-03-06 16:25:00 +0800654 public void getLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver,
markchienf2731272019-01-16 17:44:13 +0800655 boolean showEntitlementUi) {
markchien3b519632018-09-07 16:19:12 +0800656 mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ENTITLEMENT_VALUE,
657 downstream, encodeBool(showEntitlementUi), receiver));
658
659 }
660
661 private void handleGetLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver,
662 boolean showEntitlementUi) {
markchien3394e142019-04-09 15:53:24 +0800663 final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
664 if (!isTetherProvisioningRequired(config)) {
markchienf2731272019-01-16 17:44:13 +0800665 receiver.send(TETHER_ERROR_NO_ERROR, null);
666 return;
667 }
668
markchien3b519632018-09-07 16:19:12 +0800669 final int cacheValue = mEntitlementCacheValue.get(
markchienf2731272019-01-16 17:44:13 +0800670 downstream, TETHER_ERROR_ENTITLEMENT_UNKONWN);
markchienf2731272019-01-16 17:44:13 +0800671 if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
672 receiver.send(cacheValue, null);
673 } else {
markchien29b70142019-03-26 21:41:59 +0800674 ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
markchien3394e142019-04-09 15:53:24 +0800675 runUiTetherProvisioning(downstream, config.subId, proxy);
markchienf2731272019-01-16 17:44:13 +0800676 }
677 }
markchienb6eb2c22018-07-18 14:29:20 +0800678}