blob: eb0d443f4bfc916081f6061129e2669d31b36237 [file] [log] [blame]
markchien0df2ebc42019-09-30 14:40:57 +08001/*
2 * Copyright (C) 2019 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 */
16package android.net;
17
18import static android.Manifest.permission.NETWORK_STACK;
19import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
20
21import android.annotation.NonNull;
22import android.annotation.Nullable;
23import android.net.util.SharedLog;
24import android.os.ConditionVariable;
25import android.os.IBinder;
26import android.os.RemoteCallbackList;
27import android.os.RemoteException;
28import android.os.ResultReceiver;
29import android.util.Slog;
30
31import com.android.internal.annotations.GuardedBy;
32
33import java.io.PrintWriter;
34import java.util.StringJoiner;
35
36/**
37 * Service used to communicate with the tethering, which is running in a separate module.
38 * @hide
39 */
40public class TetheringManager {
41 private static final String TAG = TetheringManager.class.getSimpleName();
42
43 private static TetheringManager sInstance;
44
45 @Nullable
46 private ITetheringConnector mConnector;
47 private TetherInternalCallback mCallback;
48 private Network mTetherUpstream;
49 private TetheringConfigurationParcel mTetheringConfiguration;
50 private TetherStatesParcel mTetherStatesParcel;
51
52 private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
53 new RemoteCallbackList<>();
54 @GuardedBy("mLog")
55 private final SharedLog mLog = new SharedLog(TAG);
56
57 private TetheringManager() { }
58
59 /**
60 * Get the TetheringManager singleton instance.
61 */
62 public static synchronized TetheringManager getInstance() {
63 if (sInstance == null) {
64 sInstance = new TetheringManager();
65 }
66 return sInstance;
67 }
68
69 private class TetheringConnection implements
70 ConnectivityModuleConnector.ModuleServiceCallback {
71 @Override
72 public void onModuleServiceConnected(@NonNull IBinder service) {
73 logi("Tethering service connected");
74 registerTetheringService(service);
75 }
76 }
77
78 private void registerTetheringService(@NonNull IBinder service) {
79 final ITetheringConnector connector = ITetheringConnector.Stub.asInterface(service);
80
81 log("Tethering service registered");
82
83 // Currently TetheringManager instance is only used by ConnectivityService and mConnector
84 // only expect to assign once when system server start and bind tethering service.
85 // STOPSHIP: Change mConnector to final before TetheringManager put into boot classpath.
86 mConnector = connector;
87 mCallback = new TetherInternalCallback();
88 try {
89 mConnector.registerTetherInternalCallback(mCallback);
90 } catch (RemoteException e) {
91 e.rethrowFromSystemServer();
92 }
93 }
94
95 private class TetherInternalCallback extends ITetherInternalCallback.Stub {
96 private final ConditionVariable mWaitForCallback = new ConditionVariable(false);
97 private static final int EVENT_CALLBACK_TIMEOUT_MS = 60_000;
98
99 @Override
100 public void onUpstreamChanged(Network network) {
101 mTetherUpstream = network;
102 reportUpstreamChanged(network);
103 }
104
105 @Override
106 public void onConfigurationChanged(TetheringConfigurationParcel config) {
107 mTetheringConfiguration = config;
108 }
109
110 @Override
111 public void onTetherStatesChanged(TetherStatesParcel states) {
112 mTetherStatesParcel = states;
113 }
114
115 @Override
116 public void onCallbackCreated(Network network, TetheringConfigurationParcel config,
117 TetherStatesParcel states) {
118 mTetherUpstream = network;
119 mTetheringConfiguration = config;
120 mTetherStatesParcel = states;
121 mWaitForCallback.open();
122 }
123
124 boolean awaitCallbackCreation() {
125 return mWaitForCallback.block(EVENT_CALLBACK_TIMEOUT_MS);
126 }
127 }
128
129 private void reportUpstreamChanged(Network network) {
130 final int length = mTetheringEventCallbacks.beginBroadcast();
131 try {
132 for (int i = 0; i < length; i++) {
133 try {
134 mTetheringEventCallbacks.getBroadcastItem(i).onUpstreamChanged(network);
135 } catch (RemoteException e) {
136 // Not really very much to do here.
137 }
138 }
139 } finally {
140 mTetheringEventCallbacks.finishBroadcast();
141 }
142 }
143
144 /**
145 * Start the tethering service. Should be called only once on device startup.
146 *
147 * <p>This method will start the tethering service either in the network stack process,
148 * or inside the system server on devices that do not support the tethering module.
149 *
150 * {@hide}
151 */
152 public void start() {
153 // Using MAINLINE_NETWORK_STACK permission after cutting off the dpendency of system server.
154 ConnectivityModuleConnector.getInstance().startModuleService(
155 ITetheringConnector.class.getName(), NETWORK_STACK,
156 new TetheringConnection());
157 log("Tethering service start requested");
158 }
159
160 /**
161 * Attempt to tether the named interface. This will setup a dhcp server
162 * on the interface, forward and NAT IP v4 packets and forward DNS requests
163 * to the best active upstream network interface. Note that if no upstream
164 * IP network interface is available, dhcp will still run and traffic will be
165 * allowed between the tethered devices and this device, though upstream net
166 * access will of course fail until an upstream network interface becomes
167 * active. Note: return value do not have any meaning. It is better to use
168 * #getTetherableIfaces() to ensure corresponding interface is available for
169 * tethering before calling #tether().
170 *
markchienb741c642019-11-27 21:20:33 +0800171 * @deprecated The only usages should be in PanService and Wifi P2P which
markchien0df2ebc42019-09-30 14:40:57 +0800172 * need direct access.
173 *
174 * {@hide}
175 */
markchienb741c642019-11-27 21:20:33 +0800176 @Deprecated
markchien0df2ebc42019-09-30 14:40:57 +0800177 public int tether(@NonNull String iface) {
178 try {
179 mConnector.tether(iface);
180 } catch (RemoteException e) {
181 e.rethrowFromSystemServer();
182 }
183 return TETHER_ERROR_NO_ERROR;
184 }
185
186 /**
187 * Stop tethering the named interface.
188 *
markchienb741c642019-11-27 21:20:33 +0800189 * @deprecated
markchien0df2ebc42019-09-30 14:40:57 +0800190 * {@hide}
191 */
markchienb741c642019-11-27 21:20:33 +0800192 @Deprecated
markchien0df2ebc42019-09-30 14:40:57 +0800193 public int untether(@NonNull String iface) {
194 try {
195 mConnector.untether(iface);
196 } catch (RemoteException e) {
197 e.rethrowFromSystemServer();
198 }
199 return TETHER_ERROR_NO_ERROR;
200 }
201
202 /**
203 * Attempt to both alter the mode of USB and Tethering of USB. WARNING: New client should not
204 * use this API anymore. All clients should use #startTethering or #stopTethering which
205 * encapsulate proper entitlement logic. If the API is used and an entitlement check is needed,
206 * downstream USB tethering will be enabled but will not have any upstream.
207 *
markchienb741c642019-11-27 21:20:33 +0800208 * @deprecated
markchien0df2ebc42019-09-30 14:40:57 +0800209 * {@hide}
210 */
markchienb741c642019-11-27 21:20:33 +0800211 @Deprecated
markchien0df2ebc42019-09-30 14:40:57 +0800212 public int setUsbTethering(boolean enable) {
213 try {
214 mConnector.setUsbTethering(enable);
215 } catch (RemoteException e) {
216 e.rethrowFromSystemServer();
217 }
218 return TETHER_ERROR_NO_ERROR;
219 }
220
221 /**
222 * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
223 * fails, stopTethering will be called automatically.
224 *
225 * {@hide}
226 */
227 // TODO: improve the usage of ResultReceiver, b/145096122
228 public void startTethering(int type, @NonNull ResultReceiver receiver,
229 boolean showProvisioningUi) {
230 try {
231 mConnector.startTethering(type, receiver, showProvisioningUi);
232 } catch (RemoteException e) {
233 e.rethrowFromSystemServer();
234 }
235 }
236
237 /**
238 * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
239 * applicable.
240 *
241 * {@hide}
242 */
243 public void stopTethering(int type) {
244 try {
245 mConnector.stopTethering(type);
246 } catch (RemoteException e) {
247 e.rethrowFromSystemServer();
248 }
249 }
250
251 /**
252 * Request the latest value of the tethering entitlement check.
253 *
254 * Note: Allow privileged apps who have TETHER_PRIVILEGED permission to access. If it turns
255 * out some such apps are observed to abuse this API, change to per-UID limits on this API
256 * if it's really needed.
257 */
258 // TODO: improve the usage of ResultReceiver, b/145096122
259 public void requestLatestTetheringEntitlementResult(int type, @NonNull ResultReceiver receiver,
260 boolean showEntitlementUi) {
261 try {
262 mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
263 } catch (RemoteException e) {
264 e.rethrowFromSystemServer();
265 }
266 }
267
268 /**
269 * Register tethering event callback.
270 *
271 * {@hide}
272 */
273 public void registerTetheringEventCallback(@NonNull ITetheringEventCallback callback) {
274 mTetheringEventCallbacks.register(callback);
275 }
276
277 /**
278 * Unregister tethering event callback.
279 *
280 * {@hide}
281 */
282 public void unregisterTetheringEventCallback(@NonNull ITetheringEventCallback callback) {
283 mTetheringEventCallbacks.unregister(callback);
284 }
285
286 /**
287 * Get a more detailed error code after a Tethering or Untethering
288 * request asynchronously failed.
289 *
290 * {@hide}
291 */
292 public int getLastTetherError(@NonNull String iface) {
293 if (!mCallback.awaitCallbackCreation()) {
294 throw new NullPointerException("callback was not ready yet");
295 }
296 if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
297
298 int i = 0;
299 for (String errored : mTetherStatesParcel.erroredIfaceList) {
300 if (iface.equals(errored)) return mTetherStatesParcel.lastErrorList[i];
301
302 i++;
303 }
304 return TETHER_ERROR_NO_ERROR;
305 }
306
307 /**
308 * Get the list of regular expressions that define any tetherable
309 * USB network interfaces. If USB tethering is not supported by the
310 * device, this list should be empty.
311 *
312 * {@hide}
313 */
314 public @NonNull String[] getTetherableUsbRegexs() {
315 if (!mCallback.awaitCallbackCreation()) {
316 throw new NullPointerException("callback was not ready yet");
317 }
318 return mTetheringConfiguration.tetherableUsbRegexs;
319 }
320
321 /**
322 * Get the list of regular expressions that define any tetherable
323 * Wifi network interfaces. If Wifi tethering is not supported by the
324 * device, this list should be empty.
325 *
326 * {@hide}
327 */
328 public @NonNull String[] getTetherableWifiRegexs() {
329 if (!mCallback.awaitCallbackCreation()) {
330 throw new NullPointerException("callback was not ready yet");
331 }
332 return mTetheringConfiguration.tetherableWifiRegexs;
333 }
334
335 /**
336 * Get the list of regular expressions that define any tetherable
337 * Bluetooth network interfaces. If Bluetooth tethering is not supported by the
338 * device, this list should be empty.
339 *
340 * {@hide}
341 */
342 public @NonNull String[] getTetherableBluetoothRegexs() {
343 if (!mCallback.awaitCallbackCreation()) {
344 throw new NullPointerException("callback was not ready yet");
345 }
346 return mTetheringConfiguration.tetherableBluetoothRegexs;
347 }
348
349 /**
350 * Get the set of tetherable, available interfaces. This list is limited by
351 * device configuration and current interface existence.
352 *
353 * {@hide}
354 */
355 public @NonNull String[] getTetherableIfaces() {
356 if (!mCallback.awaitCallbackCreation()) {
357 throw new NullPointerException("callback was not ready yet");
358 }
359 if (mTetherStatesParcel == null) return new String[0];
360 return mTetherStatesParcel.availableList;
361 }
362
363 /**
364 * Get the set of tethered interfaces.
365 *
366 * {@hide}
367 */
368 public @NonNull String[] getTetheredIfaces() {
369 if (!mCallback.awaitCallbackCreation()) {
370 throw new NullPointerException("callback was not ready yet");
371 }
372 if (mTetherStatesParcel == null) return new String[0];
373 return mTetherStatesParcel.tetheredList;
374 }
375
376 /**
377 * Get the set of interface names which attempted to tether but
378 * failed.
379 *
380 * {@hide}
381 */
382 public @NonNull String[] getTetheringErroredIfaces() {
383 if (!mCallback.awaitCallbackCreation()) {
384 throw new NullPointerException("callback was not ready yet");
385 }
386 if (mTetherStatesParcel == null) return new String[0];
387 return mTetherStatesParcel.erroredIfaceList;
388 }
389
390 /**
391 * Get the set of tethered dhcp ranges.
392 *
markchienb741c642019-11-27 21:20:33 +0800393 * @deprecated This API just return the default value which is not used in DhcpServer.
markchien0df2ebc42019-09-30 14:40:57 +0800394 * {@hide}
395 */
markchienb741c642019-11-27 21:20:33 +0800396 @Deprecated
markchien0df2ebc42019-09-30 14:40:57 +0800397 public @NonNull String[] getTetheredDhcpRanges() {
398 if (!mCallback.awaitCallbackCreation()) {
399 throw new NullPointerException("callback was not ready yet");
400 }
401 return mTetheringConfiguration.legacyDhcpRanges;
402 }
403
404 /**
405 * Check if the device allows for tethering.
406 *
407 * {@hide}
408 */
409 public boolean hasTetherableConfiguration() {
410 if (!mCallback.awaitCallbackCreation()) {
411 throw new NullPointerException("callback was not ready yet");
412 }
413 final boolean hasDownstreamConfiguration =
414 (mTetheringConfiguration.tetherableUsbRegexs.length != 0)
415 || (mTetheringConfiguration.tetherableWifiRegexs.length != 0)
416 || (mTetheringConfiguration.tetherableBluetoothRegexs.length != 0);
417 final boolean hasUpstreamConfiguration =
418 (mTetheringConfiguration.preferredUpstreamIfaceTypes.length != 0)
419 || mTetheringConfiguration.chooseUpstreamAutomatically;
420
421 return hasDownstreamConfiguration && hasUpstreamConfiguration;
422 }
423
424 /**
425 * Log a message in the local log.
426 */
427 private void log(@NonNull String message) {
428 synchronized (mLog) {
429 mLog.log(message);
430 }
431 }
432
433 /**
434 * Log a condition that should never happen.
435 */
436 private void logWtf(@NonNull String message, @Nullable Throwable e) {
437 Slog.wtf(TAG, message);
438 synchronized (mLog) {
439 mLog.e(message, e);
440 }
441 }
442
443 /**
444 * Log a ERROR level message in the local and system logs.
445 */
446 private void loge(@NonNull String message, @Nullable Throwable e) {
447 synchronized (mLog) {
448 mLog.e(message, e);
449 }
450 }
451
452 /**
453 * Log a INFO level message in the local and system logs.
454 */
455 private void logi(@NonNull String message) {
456 synchronized (mLog) {
457 mLog.i(message);
458 }
459 }
460
461 /**
462 * Dump TetheringManager logs to the specified {@link PrintWriter}.
463 */
464 public void dump(@NonNull PrintWriter pw) {
465 // dump is thread-safe on SharedLog
466 mLog.dump(null, pw, null);
467
468 pw.print("subId: ");
469 pw.println(mTetheringConfiguration.subId);
470
471 dumpStringArray(pw, "tetherableUsbRegexs",
472 mTetheringConfiguration.tetherableUsbRegexs);
473 dumpStringArray(pw, "tetherableWifiRegexs",
474 mTetheringConfiguration.tetherableWifiRegexs);
475 dumpStringArray(pw, "tetherableBluetoothRegexs",
476 mTetheringConfiguration.tetherableBluetoothRegexs);
477
478 pw.print("isDunRequired: ");
479 pw.println(mTetheringConfiguration.isDunRequired);
480
481 pw.print("chooseUpstreamAutomatically: ");
482 pw.println(mTetheringConfiguration.chooseUpstreamAutomatically);
483
484 dumpStringArray(pw, "legacyDhcpRanges", mTetheringConfiguration.legacyDhcpRanges);
485 dumpStringArray(pw, "defaultIPv4DNS", mTetheringConfiguration.defaultIPv4DNS);
486
487 dumpStringArray(pw, "provisioningApp", mTetheringConfiguration.provisioningApp);
488 pw.print("provisioningAppNoUi: ");
489 pw.println(mTetheringConfiguration.provisioningAppNoUi);
490
491 pw.print("enableLegacyDhcpServer: ");
492 pw.println(mTetheringConfiguration.enableLegacyDhcpServer);
493
494 pw.println();
495 }
496
497 private static void dumpStringArray(@NonNull PrintWriter pw, @NonNull String label,
498 @Nullable String[] values) {
499 pw.print(label);
500 pw.print(": ");
501
502 if (values != null) {
503 final StringJoiner sj = new StringJoiner(", ", "[", "]");
504 for (String value : values) sj.add(value);
505
506 pw.print(sj.toString());
507 } else {
508 pw.print("null");
509 }
510
511 pw.println();
512 }
513}