blob: 25fab9e403a193f009bbed673565787d09bb626c [file] [log] [blame]
Erik Kline5a7c8a02017-04-30 19:36:15 +09001/*
2 * Copyright (C) 2017 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
Erik Kline11854592017-06-15 18:06:34 +090019import static com.android.internal.util.BitUtils.uint16;
20
Erik Kline5a7c8a02017-04-30 19:36:15 +090021import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
Erik Klinef4b6e342017-04-25 19:19:59 +090022import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
23import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
Erik Klinea0885002017-07-12 00:15:26 +090024import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
Erik Klinef4b6e342017-04-25 19:19:59 +090025import android.os.Handler;
Erik Kline5a7c8a02017-04-30 19:36:15 +090026import android.os.RemoteException;
Erik Klinef4b6e342017-04-25 19:19:59 +090027import android.net.util.SharedLog;
Erik Kline5a7c8a02017-04-30 19:36:15 +090028
Erik Kline7990aef2017-06-01 20:11:25 +090029import java.util.ArrayList;
30
Erik Kline5a7c8a02017-04-30 19:36:15 +090031
32/**
33 * Capture tethering dependencies, for injection.
34 *
35 * @hide
36 */
37public class OffloadHardwareInterface {
38 private static final String TAG = OffloadHardwareInterface.class.getSimpleName();
Erik Kline9a5b02a2017-07-12 15:46:54 +090039 private static final String YIELDS = " -> ";
Erik Klinec87cd412017-07-07 17:38:30 +090040 // Change this value to control whether tether offload is enabled or
41 // disabled by default in the absence of an explicit Settings value.
42 // See accompanying unittest to distinguish 0 from non-0 values.
Erik Klined0918912017-07-25 12:18:56 +090043 private static final int DEFAULT_TETHER_OFFLOAD_DISABLED = 1;
Erik Kline11854592017-06-15 18:06:34 +090044 private static final String NO_INTERFACE_NAME = "";
45 private static final String NO_IPV4_ADDRESS = "";
46 private static final String NO_IPV4_GATEWAY = "";
Erik Kline5a7c8a02017-04-30 19:36:15 +090047
48 private static native boolean configOffload();
49
Erik Klinef4b6e342017-04-25 19:19:59 +090050 private final Handler mHandler;
51 private final SharedLog mLog;
Erik Kline5a7c8a02017-04-30 19:36:15 +090052 private IOffloadControl mOffloadControl;
Erik Klinef4b6e342017-04-25 19:19:59 +090053 private TetheringOffloadCallback mTetheringOffloadCallback;
54 private ControlCallback mControlCallback;
Erik Kline5a7c8a02017-04-30 19:36:15 +090055
Erik Klinef4b6e342017-04-25 19:19:59 +090056 public static class ControlCallback {
Erik Klinea0885002017-07-12 00:15:26 +090057 public void onStarted() {}
58 public void onStoppedError() {}
59 public void onStoppedUnsupported() {}
60 public void onSupportAvailable() {}
61 public void onStoppedLimitReached() {}
Erik Klinef4b6e342017-04-25 19:19:59 +090062
63 public void onNatTimeoutUpdate(int proto,
64 String srcAddr, int srcPort,
65 String dstAddr, int dstPort) {}
66 }
67
Erik Kline9a5b02a2017-07-12 15:46:54 +090068 public static class ForwardedStats {
69 public long rxBytes;
70 public long txBytes;
71
72 public ForwardedStats() {
73 rxBytes = 0;
74 txBytes = 0;
75 }
76
77 public void add(ForwardedStats other) {
78 rxBytes += other.rxBytes;
79 txBytes += other.txBytes;
80 }
81
82 public String toString() {
83 return String.format("rx:%s tx:%s", rxBytes, txBytes);
84 }
85 }
86
Erik Klinef4b6e342017-04-25 19:19:59 +090087 public OffloadHardwareInterface(Handler h, SharedLog log) {
88 mHandler = h;
89 mLog = log.forSubComponent(TAG);
90 }
Erik Kline5a7c8a02017-04-30 19:36:15 +090091
Erik Klinec87cd412017-07-07 17:38:30 +090092 public int getDefaultTetherOffloadDisabled() {
93 return DEFAULT_TETHER_OFFLOAD_DISABLED;
94 }
95
Erik Kline5a7c8a02017-04-30 19:36:15 +090096 public boolean initOffloadConfig() {
97 return configOffload();
98 }
99
Erik Klinef4b6e342017-04-25 19:19:59 +0900100 public boolean initOffloadControl(ControlCallback controlCb) {
101 mControlCallback = controlCb;
102
Erik Kline5a7c8a02017-04-30 19:36:15 +0900103 if (mOffloadControl == null) {
104 try {
105 mOffloadControl = IOffloadControl.getService();
106 } catch (RemoteException e) {
Erik Klinef4b6e342017-04-25 19:19:59 +0900107 mLog.e("tethering offload control not supported: " + e);
Erik Kline5a7c8a02017-04-30 19:36:15 +0900108 return false;
109 }
110 }
111
Erik Kline248e7362017-07-04 13:39:48 +0900112 final String logmsg = String.format("initOffloadControl(%s)",
113 (controlCb == null) ? "null"
114 : "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
115
Erik Klinea0885002017-07-12 00:15:26 +0900116 mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback, mLog);
Erik Klinef4b6e342017-04-25 19:19:59 +0900117 final CbResults results = new CbResults();
118 try {
119 mOffloadControl.initOffload(
120 mTetheringOffloadCallback,
121 (boolean success, String errMsg) -> {
122 results.success = success;
123 results.errMsg = errMsg;
124 });
125 } catch (RemoteException e) {
Erik Kline248e7362017-07-04 13:39:48 +0900126 record(logmsg, e);
Erik Klinef4b6e342017-04-25 19:19:59 +0900127 return false;
128 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900129
Erik Kline248e7362017-07-04 13:39:48 +0900130 record(logmsg, results);
Erik Klinef4b6e342017-04-25 19:19:59 +0900131 return results.success;
Erik Kline5a7c8a02017-04-30 19:36:15 +0900132 }
133
134 public void stopOffloadControl() {
Erik Klinef4b6e342017-04-25 19:19:59 +0900135 if (mOffloadControl != null) {
136 try {
137 mOffloadControl.stopOffload(
138 (boolean success, String errMsg) -> {
139 if (!success) mLog.e("stopOffload failed: " + errMsg);
140 });
141 } catch (RemoteException e) {
142 mLog.e("failed to stopOffload: " + e);
143 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900144 }
145 mOffloadControl = null;
Erik Klinef4b6e342017-04-25 19:19:59 +0900146 mTetheringOffloadCallback = null;
147 mControlCallback = null;
Erik Kline248e7362017-07-04 13:39:48 +0900148 mLog.log("stopOffloadControl()");
Erik Klinef4b6e342017-04-25 19:19:59 +0900149 }
150
Erik Kline9a5b02a2017-07-12 15:46:54 +0900151 public ForwardedStats getForwardedStats(String upstream) {
152 final String logmsg = String.format("getForwardedStats(%s)", upstream);
153
154 final ForwardedStats stats = new ForwardedStats();
155 try {
156 mOffloadControl.getForwardedStats(
157 upstream,
158 (long rxBytes, long txBytes) -> {
159 stats.rxBytes = (rxBytes > 0) ? rxBytes : 0;
160 stats.txBytes = (txBytes > 0) ? txBytes : 0;
161 });
162 } catch (RemoteException e) {
163 record(logmsg, e);
164 return stats;
165 }
166
167 mLog.log(logmsg + YIELDS + stats);
168 return stats;
169 }
170
Erik Kline32179ff2017-07-04 18:28:11 +0900171 public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
172 final String logmsg = String.format("setLocalPrefixes([%s])",
173 String.join(",", localPrefixes));
174
175 final CbResults results = new CbResults();
176 try {
177 mOffloadControl.setLocalPrefixes(localPrefixes,
178 (boolean success, String errMsg) -> {
179 results.success = success;
180 results.errMsg = errMsg;
181 });
182 } catch (RemoteException e) {
183 record(logmsg, e);
184 return false;
185 }
186
187 record(logmsg, results);
188 return results.success;
189 }
190
Erik Kline7990aef2017-06-01 20:11:25 +0900191 public boolean setUpstreamParameters(
192 String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
Erik Kline248e7362017-07-04 13:39:48 +0900193 iface = (iface != null) ? iface : NO_INTERFACE_NAME;
194 v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS;
195 v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY;
196 v6gws = (v6gws != null) ? v6gws : new ArrayList<>();
197
198 final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
199 iface, v4addr, v4gateway, String.join(",", v6gws));
Erik Kline11854592017-06-15 18:06:34 +0900200
Erik Kline7990aef2017-06-01 20:11:25 +0900201 final CbResults results = new CbResults();
202 try {
203 mOffloadControl.setUpstreamParameters(
204 iface, v4addr, v4gateway, v6gws,
205 (boolean success, String errMsg) -> {
206 results.success = success;
207 results.errMsg = errMsg;
208 });
209 } catch (RemoteException e) {
Erik Kline248e7362017-07-04 13:39:48 +0900210 record(logmsg, e);
Erik Kline7990aef2017-06-01 20:11:25 +0900211 return false;
212 }
213
Erik Kline248e7362017-07-04 13:39:48 +0900214 record(logmsg, results);
Erik Kline7990aef2017-06-01 20:11:25 +0900215 return results.success;
216 }
217
Erik Kline248e7362017-07-04 13:39:48 +0900218 private void record(String msg, Throwable t) {
Erik Kline9a5b02a2017-07-12 15:46:54 +0900219 mLog.e(msg + YIELDS + "exception: " + t);
Erik Kline248e7362017-07-04 13:39:48 +0900220 }
221
222 private void record(String msg, CbResults results) {
Erik Kline9a5b02a2017-07-12 15:46:54 +0900223 final String logmsg = msg + YIELDS + results;
Erik Kline248e7362017-07-04 13:39:48 +0900224 if (!results.success) {
225 mLog.e(logmsg);
226 } else {
227 mLog.log(logmsg);
228 }
229 }
230
Erik Klinef4b6e342017-04-25 19:19:59 +0900231 private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
232 public final Handler handler;
233 public final ControlCallback controlCb;
Erik Klinea0885002017-07-12 00:15:26 +0900234 public final SharedLog log;
Erik Klinef4b6e342017-04-25 19:19:59 +0900235
Erik Klinea0885002017-07-12 00:15:26 +0900236 public TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
Erik Klinef4b6e342017-04-25 19:19:59 +0900237 handler = h;
238 controlCb = cb;
Erik Klinea0885002017-07-12 00:15:26 +0900239 log = sharedLog;
Erik Klinef4b6e342017-04-25 19:19:59 +0900240 }
241
242 @Override
243 public void onEvent(int event) {
Erik Klinea0885002017-07-12 00:15:26 +0900244 handler.post(() -> {
245 switch (event) {
246 case OffloadCallbackEvent.OFFLOAD_STARTED:
247 controlCb.onStarted();
248 break;
249 case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
250 controlCb.onStoppedError();
251 break;
252 case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
253 controlCb.onStoppedUnsupported();
254 break;
255 case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
256 controlCb.onSupportAvailable();
257 break;
258 case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
259 controlCb.onStoppedLimitReached();
260 break;
261 default:
262 log.e("Unsupported OffloadCallbackEvent: " + event);
263 }
264 });
Erik Klinef4b6e342017-04-25 19:19:59 +0900265 }
266
267 @Override
268 public void updateTimeout(NatTimeoutUpdate params) {
269 handler.post(() -> {
270 controlCb.onNatTimeoutUpdate(
271 params.proto,
Erik Kline11854592017-06-15 18:06:34 +0900272 params.src.addr, uint16(params.src.port),
273 params.dst.addr, uint16(params.dst.port));
Erik Klinef4b6e342017-04-25 19:19:59 +0900274 });
275 }
276 }
277
278 private static class CbResults {
279 boolean success;
280 String errMsg;
Erik Kline248e7362017-07-04 13:39:48 +0900281
282 public String toString() {
283 if (success) {
284 return "ok";
285 } else {
286 return "fail: " + errMsg;
287 }
288 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900289 }
290}