diff options
author | Yang Sun <sunytt@google.com> | 2024-01-25 09:56:07 +0800 |
---|---|---|
committer | Yang Sun <sunytt@google.com> | 2024-02-26 17:52:20 +0800 |
commit | d41c1ff7e17f83eb6eae04268392d1069dc88d7d (patch) | |
tree | b1d391f8b746783f7174e5cde3e6ad9485d33c4f | |
parent | 12a11b59a345e671a6832aee066f3244daef96ba (diff) | |
download | ot-br-posix-d41c1ff7e17f83eb6eae04268392d1069dc88d7d.tar.gz |
[BBR] Send full list of multicast listening addresses
When there is an update in the multicast listening addresses or update
with the BBR state, send the BBR state including full list of the listening
addresses in the IOtDaemonCallback to system server.
Bug: 321624274
Test: atest ThreadNetworkIntegrationTests
Change-Id: I49f4f7bbd9c1e733e861b3518f0602dd96700ca8
7 files changed, 144 insertions, 68 deletions
diff --git a/src/android/aidl/com/android/server/thread/openthread/BackboneRouterState.aidl b/src/android/aidl/com/android/server/thread/openthread/BackboneRouterState.aidl new file mode 100644 index 00000000..22bb3ba5 --- /dev/null +++ b/src/android/aidl/com/android/server/thread/openthread/BackboneRouterState.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.android.server.thread.openthread; + +/** + * Contains all backbone router states which the system_server and/or client apps care about. + */ +parcelable BackboneRouterState { + // true when multicast forwarding should be enabled when BackboneRoute is primary, false + // otherwise. + boolean multicastForwardingEnabled; + + // The list of multicast group address subscribed in Thread network + List<String> listeningAddresses; +} diff --git a/src/android/aidl/com/android/server/thread/openthread/IOtDaemonCallback.aidl b/src/android/aidl/com/android/server/thread/openthread/IOtDaemonCallback.aidl index 28686b10..afc07959 100644 --- a/src/android/aidl/com/android/server/thread/openthread/IOtDaemonCallback.aidl +++ b/src/android/aidl/com/android/server/thread/openthread/IOtDaemonCallback.aidl @@ -28,6 +28,7 @@ package com.android.server.thread.openthread; +import com.android.server.thread.openthread.BackboneRouterState; import com.android.server.thread.openthread.Ipv6AddressInfo; import com.android.server.thread.openthread.OtDaemonState; @@ -54,14 +55,12 @@ oneway interface IOtDaemonCallback { void onAddressChanged(in Ipv6AddressInfo addressInfo, boolean isAdded); /** - * Called when multicast forwarding listening address has been changed. + * Called when backbone router state or multicast forwarding listening addresses has been + * changed. * - * @param address the IPv6 address in bytes which has been updated. This is a multicast - * address registered by multicast listeners - * @param isAdded {@code true} if this multicast address is being added; - * Otherwise, this multicast address is being removed + * @param bbrState the backbone router state */ - void onMulticastForwardingAddressChanged(in byte[] ipv6Address, boolean isAdded); + void onBackboneRouterStateChanged(in BackboneRouterState bbrState); /** * Called when Thread enabled state has changed. Valid values are STATE_* defined in diff --git a/src/android/aidl/com/android/server/thread/openthread/OtDaemonState.aidl b/src/android/aidl/com/android/server/thread/openthread/OtDaemonState.aidl index 5d4fbb88..c13a9492 100644 --- a/src/android/aidl/com/android/server/thread/openthread/OtDaemonState.aidl +++ b/src/android/aidl/com/android/server/thread/openthread/OtDaemonState.aidl @@ -48,6 +48,4 @@ parcelable OtDaemonState { // Active Oprational Dataset encoded as Thread TLVs. Empty array means the dataset doesn't // exist byte[] pendingDatasetTlvs; - - boolean multicastForwardingEnabled; } diff --git a/src/android/java/com/android/server/thread/openthread/testing/FakeOtDaemon.java b/src/android/java/com/android/server/thread/openthread/testing/FakeOtDaemon.java index 6cfe8d95..96d5db07 100644 --- a/src/android/java/com/android/server/thread/openthread/testing/FakeOtDaemon.java +++ b/src/android/java/com/android/server/thread/openthread/testing/FakeOtDaemon.java @@ -39,6 +39,7 @@ import android.os.IBinder.DeathRecipient; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import com.android.server.thread.openthread.BackboneRouterState; import com.android.server.thread.openthread.BorderRouterConfigurationParcel; import com.android.server.thread.openthread.IChannelMasksReceiver; import com.android.server.thread.openthread.INsdPublisher; @@ -48,6 +49,7 @@ import com.android.server.thread.openthread.IOtStatusReceiver; import com.android.server.thread.openthread.OtDaemonState; import java.time.Duration; +import java.util.ArrayList; import java.util.NoSuchElementException; /** A fake implementation of the {@link IOtDaemon} AIDL API for testing. */ @@ -66,6 +68,7 @@ public final class FakeOtDaemon extends IOtDaemon.Stub { private final Handler mHandler; private final OtDaemonState mState; + private final BackboneRouterState mBbrState; private int mThreadEnabled = OT_STATE_ENABLED; private int mChannelMasksReceiverOtError = OT_ERROR_NONE; private int mSupportedChannelMask = 0x07FFF800; // from channel 11 to 26 @@ -90,7 +93,9 @@ public final class FakeOtDaemon extends IOtDaemon.Stub { mState.deviceRole = OT_DEVICE_ROLE_DISABLED; mState.activeDatasetTlvs = new byte[0]; mState.pendingDatasetTlvs = new byte[0]; - mState.multicastForwardingEnabled = false; + mBbrState = new BackboneRouterState(); + mBbrState.multicastForwardingEnabled = false; + mBbrState.listeningAddresses = new ArrayList<>(); } @Override @@ -167,6 +172,7 @@ public final class FakeOtDaemon extends IOtDaemon.Stub { mCallbackListenerId = listenerId; mHandler.post(() -> onStateChanged(mState, mCallbackListenerId)); + mHandler.post(() -> onBackboneRouterStateChanged(mBbrState)); } @Nullable @@ -191,9 +197,10 @@ public final class FakeOtDaemon extends IOtDaemon.Stub { () -> { mState.deviceRole = OT_DEVICE_ROLE_LEADER; mState.activeDatasetTlvs = activeDataset.clone(); - mState.multicastForwardingEnabled = true; + mBbrState.multicastForwardingEnabled = true; onStateChanged(mState, PROACTIVE_LISTENER_ID); + onBackboneRouterStateChanged(mBbrState); try { receiver.onSuccess(); } catch (RemoteException e) { @@ -205,14 +212,13 @@ public final class FakeOtDaemon extends IOtDaemon.Stub { private void onStateChanged(OtDaemonState state, long listenerId) { try { - // Make a copy of mState so that clients won't keep a direct reference to it + // Make a copy of state so that clients won't keep a direct reference to it OtDaemonState copyState = new OtDaemonState(); copyState.isInterfaceUp = state.isInterfaceUp; copyState.deviceRole = state.deviceRole; copyState.partitionId = state.partitionId; copyState.activeDatasetTlvs = state.activeDatasetTlvs.clone(); copyState.pendingDatasetTlvs = state.pendingDatasetTlvs.clone(); - copyState.multicastForwardingEnabled = state.multicastForwardingEnabled; mCallback.onStateChanged(copyState, listenerId); } catch (RemoteException e) { @@ -220,6 +226,18 @@ public final class FakeOtDaemon extends IOtDaemon.Stub { } } + private void onBackboneRouterStateChanged(BackboneRouterState state) { + try { + // Make a copy of state so that clients won't keep a direct reference to it + BackboneRouterState copyState = new BackboneRouterState(); + copyState.multicastForwardingEnabled = state.multicastForwardingEnabled; + copyState.listeningAddresses = new ArrayList<>(state.listeningAddresses); + mCallback.onBackboneRouterStateChanged(copyState); + } catch (RemoteException e) { + throw new AssertionError(e); + } + } + /** Sets the {@link RemoteException} which will be thrown from {@link #join}. */ public void setJoinException(RemoteException exception) { mJoinException = exception; diff --git a/src/android/otdaemon_server.cpp b/src/android/otdaemon_server.cpp index 599e1c9f..005400b6 100644 --- a/src/android/otdaemon_server.cpp +++ b/src/android/otdaemon_server.cpp @@ -151,6 +151,10 @@ void OtDaemonServer::StateCallback(otChangedFlags aFlags) mCallback->onStateChanged(mState, -1); } } + if (aFlags & OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE) + { + mCallback->onBackboneRouterStateChanged(GetBackboneRouterState()); + } } void OtDaemonServer::AddressCallback(const otIp6AddressInfo *aAddressInfo, bool aIsAdded, void *aBinderServer) @@ -257,41 +261,56 @@ exit: } } -void OtDaemonServer::HandleBackboneMulticastListenerEvent(void *aBinderServer, - otBackboneRouterMulticastListenerEvent aEvent, - const otIp6Address *aAddress) +BackboneRouterState OtDaemonServer::GetBackboneRouterState() { - OtDaemonServer *thisServer = static_cast<OtDaemonServer *>(aBinderServer); - - bool isAdded; - std::vector<uint8_t> addressBytes(aAddress->mFields.m8, BYTE_ARR_END(aAddress->mFields.m8)); - char addressString[OT_IP6_ADDRESS_STRING_SIZE]; + BackboneRouterState state; + otBackboneRouterState bbrState = otBackboneRouterGetState(GetOtInstance()); + otBackboneRouterMulticastListenerInfo info; + otBackboneRouterMulticastListenerIterator iter = OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ITERATOR_INIT; + state.listeningAddresses = std::vector<std::string>(); - otIp6AddressToString(aAddress, addressString, sizeof(addressString)); + if (mCallback == nullptr) + { + otbrLogWarning("OT daemon callback is not set"); + return state; + } - switch (aEvent) + switch (bbrState) { - case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED: - isAdded = true; + case OT_BACKBONE_ROUTER_STATE_DISABLED: + case OT_BACKBONE_ROUTER_STATE_SECONDARY: + state.multicastForwardingEnabled = false; break; - case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED: - isAdded = false; + case OT_BACKBONE_ROUTER_STATE_PRIMARY: + state.multicastForwardingEnabled = true; break; - default: - otbrLogErr("Got BackboneMulticastListenerEvent with unsupported event: %d", aEvent); - assert(false); } + otbrLogInfo("Updating backbone router state (bbr state = %d)", bbrState); - otbrLogDebug("Multicast forwarding address changed, %s is %s", addressString, isAdded ? "added" : "removed"); - - if (thisServer->mCallback != nullptr) + while (otBackboneRouterMulticastListenerGetNext(GetOtInstance(), &iter, &info) == OT_ERROR_NONE) { - thisServer->mCallback->onMulticastForwardingAddressChanged(addressBytes, isAdded); - } - else - { - otbrLogWarning("OT daemon callback is not set"); + char string[OT_IP6_ADDRESS_STRING_SIZE]; + + otIp6AddressToString(&info.mAddress, string, sizeof(string)); + state.listeningAddresses.push_back(string); } + + return state; +} + +void OtDaemonServer::HandleBackboneMulticastListenerEvent(void *aBinderServer, + otBackboneRouterMulticastListenerEvent aEvent, + const otIp6Address *aAddress) +{ + OtDaemonServer *thisServer = static_cast<OtDaemonServer *>(aBinderServer); + char addressString[OT_IP6_ADDRESS_STRING_SIZE]; + + otIp6AddressToString(aAddress, addressString, sizeof(addressString)); + + otbrLogDebug("Multicast forwarding address changed, %s is %s", addressString, + (aEvent == OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED) ? "added" : "removed"); + + thisServer->mCallback->onBackboneRouterStateChanged(thisServer->GetBackboneRouterState()); } otInstance *OtDaemonServer::GetOtInstance() @@ -439,6 +458,7 @@ Status OtDaemonServer::registerStateCallback(const std::shared_ptr<IOtDaemonCall RefreshOtDaemonState(/* aFlags */ 0xffffffff); mCallback->onStateChanged(mState, listenerId); mCallback->onThreadEnabledChanged(mThreadEnabled); + mCallback->onBackboneRouterStateChanged(GetBackboneRouterState()); exit: return Status::ok(); @@ -494,23 +514,6 @@ bool OtDaemonServer::RefreshOtDaemonState(otChangedFlags aFlags) haveUpdates = true; } - if (aFlags & OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE) - { - otBackboneRouterState state = otBackboneRouterGetState(GetOtInstance()); - - switch (state) - { - case OT_BACKBONE_ROUTER_STATE_DISABLED: - case OT_BACKBONE_ROUTER_STATE_SECONDARY: - mState.multicastForwardingEnabled = false; - break; - case OT_BACKBONE_ROUTER_STATE_PRIMARY: - mState.multicastForwardingEnabled = true; - break; - } - haveUpdates = true; - } - if (isAttached() && !mState.activeDatasetTlvs.empty() && mJoinReceiver != nullptr) { mJoinReceiver->onSuccess(); diff --git a/src/android/otdaemon_server.hpp b/src/android/otdaemon_server.hpp index 70403b9a..ab1a50ea 100644 --- a/src/android/otdaemon_server.hpp +++ b/src/android/otdaemon_server.hpp @@ -51,6 +51,7 @@ namespace Android { using BinderDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient; using ScopedFileDescriptor = ::ndk::ScopedFileDescriptor; using Status = ::ndk::ScopedAStatus; +using aidl::com::android::server::thread::openthread::BackboneRouterState; using aidl::com::android::server::thread::openthread::BnOtDaemon; using aidl::com::android::server::thread::openthread::BorderRouterConfigurationParcel; using aidl::com::android::server::thread::openthread::IChannelMasksReceiver; @@ -112,18 +113,19 @@ private: void DetachGracefullyCallback(void); static void SendMgmtPendingSetCallback(otError aResult, void *aBinderServer); - static void BinderDeathCallback(void *aBinderServer); - void StateCallback(otChangedFlags aFlags); - static void AddressCallback(const otIp6AddressInfo *aAddressInfo, bool aIsAdded, void *aBinderServer); - static void ReceiveCallback(otMessage *aMessage, void *aBinderServer); - void ReceiveCallback(otMessage *aMessage); - void TransmitCallback(void); - static void HandleBackboneMulticastListenerEvent(void *aBinderServer, - otBackboneRouterMulticastListenerEvent aEvent, - const otIp6Address *aAddress); - void PushTelemetryIfConditionMatch(); - void updateThreadEnabledState(const int aEnabled, const std::shared_ptr<IOtStatusReceiver> &aReceiver); - void enableThread(const std::shared_ptr<IOtStatusReceiver> &aReceiver); + static void BinderDeathCallback(void *aBinderServer); + void StateCallback(otChangedFlags aFlags); + static void AddressCallback(const otIp6AddressInfo *aAddressInfo, bool aIsAdded, void *aBinderServer); + static void ReceiveCallback(otMessage *aMessage, void *aBinderServer); + void ReceiveCallback(otMessage *aMessage); + void TransmitCallback(void); + BackboneRouterState GetBackboneRouterState(void); + static void HandleBackboneMulticastListenerEvent(void *aBinderServer, + otBackboneRouterMulticastListenerEvent aEvent, + const otIp6Address *aAddress); + void PushTelemetryIfConditionMatch(); + void updateThreadEnabledState(const int aEnabled, const std::shared_ptr<IOtStatusReceiver> &aReceiver); + void enableThread(const std::shared_ptr<IOtStatusReceiver> &aReceiver); int mThreadEnabled = IOtDaemon::OT_STATE_DISABLED; otbr::Ncp::ControllerOpenThread &mNcp; diff --git a/tests/android/java/com/android/server/thread/openthread/testing/FakeOtDaemonTest.java b/tests/android/java/com/android/server/thread/openthread/testing/FakeOtDaemonTest.java index e5fd72cc..adf16d20 100644 --- a/tests/android/java/com/android/server/thread/openthread/testing/FakeOtDaemonTest.java +++ b/tests/android/java/com/android/server/thread/openthread/testing/FakeOtDaemonTest.java @@ -45,6 +45,7 @@ import android.os.test.TestLooper; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import com.android.server.thread.openthread.BackboneRouterState; import com.android.server.thread.openthread.IChannelMasksReceiver; import com.android.server.thread.openthread.INsdPublisher; import com.android.server.thread.openthread.IOtDaemonCallback; @@ -120,6 +121,7 @@ public final class FakeOtDaemonTest { mFakeOtDaemon.initialize(mMockTunFd, true, mMockNsdPublisher); final AtomicReference<OtDaemonState> stateRef = new AtomicReference<>(); final AtomicLong listenerIdRef = new AtomicLong(); + final AtomicReference<BackboneRouterState> bbrStateRef = new AtomicReference<>(); mFakeOtDaemon.registerStateCallback( new IOtDaemonCallback.Default() { @@ -128,6 +130,11 @@ public final class FakeOtDaemonTest { stateRef.set(newState); listenerIdRef.set(listenerId); } + + @Override + public void onBackboneRouterStateChanged(BackboneRouterState bbrState) { + bbrStateRef.set(bbrState); + } }, 7 /* listenerId */); mTestLooper.dispatchAll(); @@ -138,8 +145,9 @@ public final class FakeOtDaemonTest { assertThat(state.deviceRole).isEqualTo(FakeOtDaemon.OT_DEVICE_ROLE_DISABLED); assertThat(state.activeDatasetTlvs).isEmpty(); assertThat(state.pendingDatasetTlvs).isEmpty(); - assertThat(state.multicastForwardingEnabled).isFalse(); assertThat(listenerIdRef.get()).isEqualTo(7); + BackboneRouterState bbrState = bbrStateRef.get(); + assertThat(bbrState.multicastForwardingEnabled).isFalse(); } @Test @@ -162,12 +170,18 @@ public final class FakeOtDaemonTest { public void join_succeed_statesAreSentBack() throws Exception { final AtomicBoolean succeedRef = new AtomicBoolean(false); final AtomicReference<OtDaemonState> stateRef = new AtomicReference<>(); + final AtomicReference<BackboneRouterState> bbrStateRef = new AtomicReference<>(); mFakeOtDaemon.registerStateCallback( new IOtDaemonCallback.Default() { @Override public void onStateChanged(OtDaemonState newState, long listenerId) { stateRef.set(newState); } + + @Override + public void onBackboneRouterStateChanged(BackboneRouterState bbrState) { + bbrStateRef.set(bbrState); + } }, 11 /* listenerId */); @@ -192,7 +206,8 @@ public final class FakeOtDaemonTest { assertThat(state.isInterfaceUp).isTrue(); assertThat(state.deviceRole).isEqualTo(FakeOtDaemon.OT_DEVICE_ROLE_LEADER); assertThat(state.activeDatasetTlvs).isEqualTo(DEFAULT_ACTIVE_DATASET_TLVS); - assertThat(state.multicastForwardingEnabled).isTrue(); + final BackboneRouterState bbrState = bbrStateRef.get(); + assertThat(bbrState.multicastForwardingEnabled).isTrue(); } @Test |