diff options
Diffstat (limited to 'common/networkstackclient')
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(); + } + } +} |