summaryrefslogtreecommitdiff
path: root/common/networkstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'common/networkstackclient')
-rw-r--r--common/networkstackclient/Android.bp15
-rw-r--r--common/networkstackclient/src/android/net/networkstack/ModuleNetworkStackClient.java104
-rw-r--r--common/networkstackclient/src/android/net/networkstack/NetworkStackClientBase.java161
3 files changed, 280 insertions, 0 deletions
diff --git a/common/networkstackclient/Android.bp b/common/networkstackclient/Android.bp
index a34a637..16fdd56 100644
--- a/common/networkstackclient/Android.bp
+++ b/common/networkstackclient/Android.bp
@@ -37,6 +37,9 @@ aidl_interface {
"3",
"4",
],
+ visibility: [
+ "//system/tools/aidl/build"
+ ],
}
aidl_interface {
@@ -84,6 +87,11 @@ aidl_interface {
"3",
"4",
],
+ // TODO: have tethering depend on networkstack-client and set visibility to private
+ visibility: [
+ "//system/tools/aidl/build",
+ "//frameworks/base/packages/Tethering"
+ ],
}
java_library {
@@ -93,9 +101,16 @@ java_library {
":framework-annotations",
"src/android/net/IpMemoryStoreClient.java",
"src/android/net/ipmemorystore/**/*.java",
+ "src/android/net/networkstack/**/*.java",
],
static_libs: [
"ipmemorystore-aidl-interfaces-V3-java",
"networkstack-aidl-interfaces-unstable-java",
],
+ visibility: [
+ "//frameworks/base/packages/Tethering",
+ "//frameworks/base/services/net",
+ "//frameworks/opt/net/wifi/service",
+ "//packages/modules/NetworkStack",
+ ]
}
diff --git a/common/networkstackclient/src/android/net/networkstack/ModuleNetworkStackClient.java b/common/networkstackclient/src/android/net/networkstack/ModuleNetworkStackClient.java
new file mode 100644
index 0000000..cfbb760
--- /dev/null
+++ b/common/networkstackclient/src/android/net/networkstack/ModuleNetworkStackClient.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.networkstack;
+
+import static android.content.Context.NETWORK_STACK_SERVICE;
+import static android.os.Build.VERSION.SDK_INT;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.INetworkStackConnector;
+import android.os.Build;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A {@link NetworkStackClientBase} implementation for use within modules (not the system server).
+ */
+public class ModuleNetworkStackClient extends NetworkStackClientBase {
+ private static final String TAG = ModuleNetworkStackClient.class.getSimpleName();
+
+ private ModuleNetworkStackClient() {}
+
+ private static ModuleNetworkStackClient sInstance;
+
+ /**
+ * Get an instance of the ModuleNetworkStackClient.
+ * @param packageContext Context to use to obtain the network stack connector.
+ */
+ @NonNull
+ public static synchronized ModuleNetworkStackClient getInstance(Context packageContext) {
+ // TODO(b/149676685): change this check to "< R" once R is defined
+ if (SDK_INT < Build.VERSION_CODES.Q
+ || (SDK_INT == Build.VERSION_CODES.Q && "REL".equals(Build.VERSION.CODENAME))) {
+ // NETWORK_STACK_SERVICE is not available through getSystemService before R
+ throw new UnsupportedOperationException(
+ "ModuleNetworkStackClient is not supported on API " + SDK_INT);
+ }
+
+ if (sInstance == null) {
+ sInstance = new ModuleNetworkStackClient();
+ sInstance.startPolling(packageContext);
+ }
+ return sInstance;
+ }
+
+ @VisibleForTesting
+ protected static synchronized void resetInstanceForTest() {
+ sInstance = null;
+ }
+
+ private void startPolling(Context context) {
+ // If the service is already registered (as it will be most of the time), do not poll and
+ // fulfill requests immediately.
+ final IBinder nss = (IBinder) context.getSystemService(NETWORK_STACK_SERVICE);
+ if (nss != null) {
+ // Calling onNetworkStackConnected here means that pending oneway Binder calls to the
+ // NetworkStack get sent from the current thread and not a worker thread; this is fine
+ // considering that those are only non-blocking, oneway Binder calls.
+ onNetworkStackConnected(INetworkStackConnector.Stub.asInterface(nss));
+ return;
+ }
+ new Thread(new PollingRunner(context)).start();
+ }
+
+ private class PollingRunner implements Runnable {
+ private final Context mContext;
+
+ private PollingRunner(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void run() {
+ // Block until the NetworkStack connector is registered in ServiceManager.
+ IBinder nss;
+ while ((nss = (IBinder) mContext.getSystemService(NETWORK_STACK_SERVICE)) == null) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while waiting for NetworkStack connector", e);
+ // Keep trying, the system would just crash without a connector
+ }
+ }
+
+ onNetworkStackConnected(INetworkStackConnector.Stub.asInterface(nss));
+ }
+ }
+}
diff --git a/common/networkstackclient/src/android/net/networkstack/NetworkStackClientBase.java b/common/networkstackclient/src/android/net/networkstack/NetworkStackClientBase.java
new file mode 100644
index 0000000..c2f7ddd
--- /dev/null
+++ b/common/networkstackclient/src/android/net/networkstack/NetworkStackClientBase.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.networkstack;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IIpMemoryStoreCallbacks;
+import android.net.INetworkMonitorCallbacks;
+import android.net.INetworkStackConnector;
+import android.net.Network;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.IDhcpServerCallbacks;
+import android.net.ip.IIpClientCallbacks;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * Utility class to obtain and communicate with the NetworkStack module.
+ */
+public abstract class NetworkStackClientBase {
+ @NonNull
+ @GuardedBy("mPendingNetStackRequests")
+ private final ArrayList<Consumer<INetworkStackConnector>> mPendingNetStackRequests =
+ new ArrayList<>();
+
+ @Nullable
+ @GuardedBy("mPendingNetStackRequests")
+ private INetworkStackConnector mConnector;
+
+ /**
+ * Create a DHCP server according to the specified parameters.
+ *
+ * <p>The server will be returned asynchronously through the provided callbacks.
+ */
+ public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params,
+ final IDhcpServerCallbacks cb) {
+ requestConnector(connector -> {
+ try {
+ connector.makeDhcpServer(ifName, params, cb);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Could not create DhcpServer", e);
+ }
+ });
+ }
+
+ /**
+ * Create an IpClient on the specified interface.
+ *
+ * <p>The IpClient will be returned asynchronously through the provided callbacks.
+ */
+ public void makeIpClient(String ifName, IIpClientCallbacks cb) {
+ requestConnector(connector -> {
+ try {
+ connector.makeIpClient(ifName, cb);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Could not create IpClient", e);
+ }
+ });
+ }
+
+ /**
+ * Create a NetworkMonitor.
+ *
+ * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
+ */
+ public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb) {
+ requestConnector(connector -> {
+ try {
+ connector.makeNetworkMonitor(network, name, cb);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Could not create NetworkMonitor", e);
+ }
+ });
+ }
+
+ /**
+ * Get an instance of the IpMemoryStore.
+ *
+ * <p>The IpMemoryStore will be returned asynchronously through the provided callbacks.
+ */
+ public void fetchIpMemoryStore(IIpMemoryStoreCallbacks cb) {
+ requestConnector(connector -> {
+ try {
+ connector.fetchIpMemoryStore(cb);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Could not fetch IpMemoryStore", e);
+ }
+ });
+ }
+
+ protected void requestConnector(@NonNull Consumer<INetworkStackConnector> request) {
+ final INetworkStackConnector connector;
+ synchronized (mPendingNetStackRequests) {
+ connector = mConnector;
+ if (connector == null) {
+ mPendingNetStackRequests.add(request);
+ return;
+ }
+ }
+
+ request.accept(connector);
+ }
+
+ /**
+ * Call this method once the NetworkStack is connected.
+ *
+ * <p>This method will cause pending oneway Binder calls for the NetworkStack to be processed on
+ * the calling thread.
+ */
+ protected void onNetworkStackConnected(@NonNull INetworkStackConnector connector) {
+ // Process the connector wait queue in order, including any items that are added
+ // while processing.
+ while (true) {
+ final ArrayList<Consumer<INetworkStackConnector>> requests;
+ synchronized (mPendingNetStackRequests) {
+ requests = new ArrayList<>(mPendingNetStackRequests);
+ mPendingNetStackRequests.clear();
+ }
+
+ for (Consumer<INetworkStackConnector> consumer : requests) {
+ consumer.accept(connector);
+ }
+
+ synchronized (mPendingNetStackRequests) {
+ if (mPendingNetStackRequests.size() == 0) {
+ // Once mConnector is non-null, no more tasks will be queued.
+ mConnector = connector;
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Used in subclasses for diagnostics (dumpsys) purposes.
+ * @return How many requests for the network stack are currently pending.
+ */
+ protected int getQueueLength() {
+ synchronized (mPendingNetStackRequests) {
+ return mPendingNetStackRequests.size();
+ }
+ }
+}