From 276384042de9ecd6f1564386e39bebb580f73524 Mon Sep 17 00:00:00 2001 From: Kangping Dong Date: Wed, 15 Nov 2023 10:26:14 +0800 Subject: [PATCH] [Thread] add service unit test skeleton Adds the Thread service unit test skeleton and make the services testable. Initially, a few trivial unit tests for existing APIs are added in ThreadNetworkControllerServiceTest.java, and more tests will be added in separate CLs later. Bug: 317555104 Change-Id: I7b9e5f3663493d8da2448568de792e4272ee1df6 --- .../ThreadNetworkControllerService.java | 92 +++++----- thread/tests/unit/Android.bp | 7 +- thread/tests/unit/AndroidTest.xml | 3 + .../ThreadNetworkControllerServiceTest.java | 163 ++++++++++++++++++ 4 files changed, 225 insertions(+), 40 deletions(-) create mode 100644 thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java index 5ae310c995..6cd0ac3bcb 100644 --- a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java +++ b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java @@ -36,7 +36,6 @@ import static android.net.thread.ThreadNetworkException.ERROR_RESOURCE_EXHAUSTED import static android.net.thread.ThreadNetworkException.ERROR_RESPONSE_BAD_FORMAT; import static android.net.thread.ThreadNetworkException.ERROR_TIMEOUT; import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_CHANNEL; -import static android.net.thread.ThreadNetworkException.ErrorCode; import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_PRIVILEGED; import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_ABORT; @@ -84,6 +83,7 @@ import android.net.thread.OperationalDatasetTimestamp; import android.net.thread.PendingOperationalDataset; import android.net.thread.ThreadNetworkController; import android.net.thread.ThreadNetworkController.DeviceRole; +import android.net.thread.ThreadNetworkException.ErrorCode; import android.os.Build; import android.os.Handler; import android.os.HandlerThread; @@ -120,8 +120,8 @@ import java.util.function.Supplier; * *

Threading model: This class is not Thread-safe and should only be accessed from the * ThreadNetworkService class. Additional attention should be paid to handle the threading code - * correctly: 1. All member fields other than `mHandler` and `mContext` MUST be accessed from - * `mHandlerThread` 2. In the @Override methods, the actual work MUST be dispatched to the + * correctly: 1. All member fields other than `mHandler` and `mContext` MUST be accessed from the + * thread of `mHandler` 2. In the @Override methods, the actual work MUST be dispatched to the * HandlerThread except for arguments or permissions checking */ @TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @@ -133,11 +133,10 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub private final Context mContext; private final Handler mHandler; - // Below member fields can only be accessed from the handler thread (`mHandlerThread`). In + // Below member fields can only be accessed from the handler thread (`mHandler`). In // particular, the constructor does not run on the handler thread, so it must not touch any of // the non-final fields, nor must it mutate any of the non-final fields inside these objects. - private final HandlerThread mHandlerThread; private final NetworkProvider mNetworkProvider; private final Supplier mOtDaemonSupplier; private final ConnectivityManager mConnectivityManager; @@ -149,8 +148,10 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub // TODO(b/308310823): read supported channel from Thread dameon private final int mSupportedChannelMask = 0x07FFF800; // from channel 11 to 26 - private IOtDaemon mOtDaemon; - private NetworkAgent mNetworkAgent; + @Nullable private IOtDaemon mOtDaemon; + @Nullable private NetworkAgent mNetworkAgent; + @Nullable private NetworkAgent mTestNetworkAgent; + private MulticastRoutingConfig mUpstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE; private MulticastRoutingConfig mDownstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE; private Network mUpstreamNetwork; @@ -164,15 +165,14 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub @VisibleForTesting ThreadNetworkControllerService( Context context, - HandlerThread handlerThread, + Handler handler, NetworkProvider networkProvider, Supplier otDaemonSupplier, ConnectivityManager connectivityManager, TunInterfaceController tunIfController, InfraInterfaceController infraIfController) { mContext = context; - mHandlerThread = handlerThread; - mHandler = new Handler(handlerThread.getLooper()); + mHandler = handler; mNetworkProvider = networkProvider; mOtDaemonSupplier = otDaemonSupplier; mConnectivityManager = connectivityManager; @@ -191,7 +191,7 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub return new ThreadNetworkControllerService( context, - handlerThread, + new Handler(handlerThread.getLooper()), networkProvider, () -> IOtDaemon.Stub.asInterface(ServiceManagerWrapper.waitForService("ot_daemon")), context.getSystemService(ConnectivityManager.class), @@ -199,14 +199,6 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub new InfraInterfaceController()); } - private static NetworkCapabilities newNetworkCapabilities() { - return new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_THREAD) - .addCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .build(); - } - private static Inet6Address bytesToInet6Address(byte[] addressBytes) { try { return (Inet6Address) Inet6Address.getByAddress(addressBytes); @@ -302,6 +294,8 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub } private IOtDaemon getOtDaemon() throws RemoteException { + checkOnHandlerThread(); + if (mOtDaemon != null) { return mOtDaemon; } @@ -310,9 +304,9 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub if (otDaemon == null) { throw new RemoteException("Internal error: failed to start OT daemon"); } - otDaemon.asBinder().linkToDeath(() -> mHandler.post(this::onOtDaemonDied), 0); otDaemon.initialize(mTunIfController.getTunFd()); otDaemon.registerStateCallback(mOtDaemonCallbackProxy, -1); + otDaemon.asBinder().linkToDeath(() -> mHandler.post(this::onOtDaemonDied), 0); mOtDaemon = otDaemon; return mOtDaemon; } @@ -427,27 +421,47 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub mHandler); } + /** Injects a {@link NetworkAgent} for testing. */ + @VisibleForTesting + void setTestNetworkAgent(@Nullable NetworkAgent testNetworkAgent) { + mTestNetworkAgent = testNetworkAgent; + } + + private NetworkAgent newNetworkAgent() { + if (mTestNetworkAgent != null) { + return mTestNetworkAgent; + } + + final NetworkCapabilities netCaps = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_THREAD) + .addCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .build(); + final NetworkScore score = + new NetworkScore.Builder() + .setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_LOCAL_NETWORK) + .build(); + return new NetworkAgent( + mContext, + mHandler.getLooper(), + TAG, + netCaps, + mLinkProperties, + newLocalNetworkConfig(), + score, + new NetworkAgentConfig.Builder().build(), + mNetworkProvider) {}; + } + private void registerThreadNetwork() { if (mNetworkAgent != null) { return; } - NetworkCapabilities netCaps = newNetworkCapabilities(); - NetworkScore score = - new NetworkScore.Builder() - .setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_LOCAL_NETWORK) - .build(); + requestThreadNetwork(); - mNetworkAgent = - new NetworkAgent( - mContext, - mHandlerThread.getLooper(), - TAG, - netCaps, - mLinkProperties, - newLocalNetworkConfig(), - score, - new NetworkAgentConfig.Builder().build(), - mNetworkProvider) {}; + + mNetworkAgent = newNetworkAgent(); mNetworkAgent.register(); mNetworkAgent.markConnected(); Log.i(TAG, "Registered Thread network"); @@ -634,7 +648,7 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub } private void checkOnHandlerThread() { - if (Looper.myLooper() != mHandlerThread.getLooper()) { + if (Looper.myLooper() != mHandler.getLooper()) { Log.wtf(TAG, "Must be on the handler thread!"); } } @@ -950,8 +964,8 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub } /** - * Handles and forwards Thread daemon callbacks. This class must be accessed from the {@code - * mHandlerThread}. + * Handles and forwards Thread daemon callbacks. This class must be accessed from the thread of + * {@code mHandler}. */ private final class OtDaemonCallbackProxy extends IOtDaemonCallback.Stub { private final Map mStateCallbacks = new HashMap<>(); diff --git a/thread/tests/unit/Android.bp b/thread/tests/unit/Android.bp index c7887bc56c..71642a1c32 100644 --- a/thread/tests/unit/Android.bp +++ b/thread/tests/unit/Android.bp @@ -39,6 +39,8 @@ android_test { "guava-android-testlib", "mockito-target-extended-minus-junit4", "net-tests-utils", + "ot-daemon-aidl-java", + "ot-daemon-testing", "service-connectivity-pre-jarjar", "service-thread-pre-jarjar", "truth", @@ -48,12 +50,15 @@ android_test { "android.test.runner", "ServiceConnectivityResources", ], - jarjar_rules: ":connectivity-jarjar-rules", jni_libs: [ + "libservice-thread-jni", + // these are needed for Extended Mockito "libdexmakerjvmtiagent", "libstaticjvmtiagent", ], + jni_uses_platform_apis: true, + jarjar_rules: ":connectivity-jarjar-rules", // Test coverage system runs on different devices. Need to // compile for all architectures. compile_multilib: "both", diff --git a/thread/tests/unit/AndroidTest.xml b/thread/tests/unit/AndroidTest.xml index 597c6a82cc..26813c1ab0 100644 --- a/thread/tests/unit/AndroidTest.xml +++ b/thread/tests/unit/AndroidTest.xml @@ -30,5 +30,8 @@