summaryrefslogtreecommitdiff
path: root/common/networkstackclient
diff options
context:
space:
mode:
authorRemi NGUYEN VAN <reminv@google.com>2020-01-07 09:55:38 +0900
committerRoshan Pius <rpius@google.com>2020-02-20 14:58:59 -0800
commit40525479f6c286962b1bdbc056b4f9d010b45a34 (patch)
tree3bdde73ea4c097c15bf644bf54e7c35891f74765 /common/networkstackclient
parente1aa745f9fd8deace324c48957c7f4ed9ac1d35c (diff)
Add ModuleNetworkStackClient
NetworkStackClientBase / ModuleNetworkStackClient extract functionality from NetworkStackClient in services.jar, only keeping what is needed for modules to communicate with the NetworkStack, and not the framework code that starts the NetworkStack (and uses hidden APIs). As the NetworkStack is started asynchronously, it is possible for it not to be registered yet right after boot, so some polling is implemented to queue requests until it is ready. NetworkStackClient will inherit from NetworkStackClientBase so that components in services.jar can access the NetworkStack, using the same asynchronous mechanism as before (execute pending requests once the service is connected). Bug: 147255753 Test: atest NetworkStackTests NetworkStackNextTests FrameworksNetTests Change-Id: I130aabb3992280d875e0d20b16bc09a9e0261fda
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();
+ }
+ }
+}