Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7becc77e authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6227479 from 7c124b19 to rvc-release

Change-Id: Ifff415aeeaa6b389f9db07a88bf6a1aba0492e42
parents b0da42f1 7c124b19
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -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",
    ]
}
+104 −0
Original line number Diff line number Diff line
/*
 * 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));
        }
    }
}
+161 −0
Original line number Diff line number Diff line
/*
 * 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();
        }
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ java_defaults {
    srcs: ["src/**/*.java", "src/**/*.kt"],
    resource_dirs: ["res"],
    static_libs: [
        "androidx.test.ext.junit",
        "androidx.test.rules",
        "kotlin-reflect",
        "mockito-target-extended-minus-junit4",
+123 −0
Original line number Diff line number Diff line
/*
 * 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.content.Context
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.Build
import android.os.IBinder
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.networkstack.apishim.ShimUtils
import org.junit.After
import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.Mock
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.never
import org.mockito.Mockito.timeout
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@RunWith(AndroidJUnit4::class)
@SmallTest
class ModuleNetworkStackClientTest {
    private val TEST_IFNAME = "testiface"
    private val TEST_NETWORK = Network(43)
    private val TEST_TIMEOUT_MS = 500L

    @Mock
    private lateinit var mContext: Context
    @Mock
    private lateinit var mConnectorBinder: IBinder
    @Mock
    private lateinit var mConnector: INetworkStackConnector
    @Mock
    private lateinit var mIpClientCb: IIpClientCallbacks
    @Mock
    private lateinit var mDhcpServerCb: IDhcpServerCallbacks
    @Mock
    private lateinit var mNetworkMonitorCb: INetworkMonitorCallbacks
    @Mock
    private lateinit var mIpMemoryStoreCb: IIpMemoryStoreCallbacks

    @Before
    fun setUp() {
        // ModuleNetworkStackClient is only available after Q
        assumeTrue(ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q))
        MockitoAnnotations.initMocks(this)
        doReturn(mConnector).`when`(mConnectorBinder).queryLocalInterface(
                INetworkStackConnector::class.qualifiedName!!)
    }

    @After
    fun tearDown() {
        ModuleNetworkStackClient.resetInstanceForTest()
    }

    @Test
    fun testIpClientServiceAvailableImmediately() {
        doReturn(mConnectorBinder).`when`(mContext).getSystemService(Context.NETWORK_STACK_SERVICE)
        ModuleNetworkStackClient.getInstance(mContext).makeIpClient(TEST_IFNAME, mIpClientCb)
        verify(mConnector).makeIpClient(TEST_IFNAME, mIpClientCb)
    }

    @Test
    fun testIpClientServiceAvailableAfterPolling() {
        ModuleNetworkStackClient.getInstance(mContext).makeIpClient(TEST_IFNAME, mIpClientCb)

        Thread.sleep(TEST_TIMEOUT_MS)
        verify(mConnector, never()).makeIpClient(any(), any())
        doReturn(mConnectorBinder).`when`(mContext).getSystemService(Context.NETWORK_STACK_SERVICE)
        // Use a longer timeout as polling can cause larger delays
        verify(mConnector, timeout(TEST_TIMEOUT_MS * 4)).makeIpClient(TEST_IFNAME, mIpClientCb)
    }

    @Test
    fun testDhcpServerAvailableImmediately() {
        doReturn(mConnectorBinder).`when`(mContext).getSystemService(Context.NETWORK_STACK_SERVICE)
        val testParams = DhcpServingParamsParcel()
        ModuleNetworkStackClient.getInstance(mContext).makeDhcpServer(TEST_IFNAME, testParams,
                mDhcpServerCb)
        verify(mConnector).makeDhcpServer(TEST_IFNAME, testParams, mDhcpServerCb)
    }

    @Test
    fun testNetworkMonitorAvailableImmediately() {
        doReturn(mConnectorBinder).`when`(mContext).getSystemService(Context.NETWORK_STACK_SERVICE)
        val testName = "NetworkMonitorName"
        ModuleNetworkStackClient.getInstance(mContext).makeNetworkMonitor(TEST_NETWORK, testName,
                mNetworkMonitorCb)
        verify(mConnector).makeNetworkMonitor(TEST_NETWORK, testName, mNetworkMonitorCb)
    }

    @Test
    fun testIpMemoryStoreAvailableImmediately() {
        doReturn(mConnectorBinder).`when`(mContext).getSystemService(Context.NETWORK_STACK_SERVICE)
        ModuleNetworkStackClient.getInstance(mContext).fetchIpMemoryStore(mIpMemoryStoreCb)
        verify(mConnector).fetchIpMemoryStore(mIpMemoryStoreCb)
    }
}
 No newline at end of file