Merge "Thread: use network time for generating dataset" into main

This commit is contained in:
Yakun Xu 2024-05-24 09:18:21 +00:00 • committed by Gerrit Code Review
commit f987ceba35
2 changed files with 66 additions and 3 deletions

View file

@ -105,6 +105,7 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
@ -131,6 +132,8 @@ import java.io.IOException;
import java.net.Inet6Address;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
@ -821,7 +824,6 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub
networkName,
supportedChannelMask,
preferredChannelMask,
Instant.now(),
new Random(),
new SecureRandom());
@ -839,9 +841,18 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub
String networkName,
int supportedChannelMask,
int preferredChannelMask,
Instant now,
Random random,
SecureRandom secureRandom) {
boolean authoritative = false;
Instant now = Instant.now();
try {
Clock clock = SystemClock.currentNetworkTimeClock();
now = clock.instant();
authoritative = true;
} catch (DateTimeException e) {
Log.w(TAG, "Failed to get authoritative time", e);
}
int panId = random.nextInt(/* bound= */ 0xffff);
final byte[] meshLocalPrefix = newRandomBytes(random, LENGTH_MESH_LOCAL_PREFIX_BITS / 8);
meshLocalPrefix[0] = MESH_LOCAL_PREFIX_FIRST_BYTE;
@ -855,7 +866,7 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub
return new ActiveOperationalDataset.Builder()
.setActiveTimestamp(
new OperationalDatasetTimestamp(
now.getEpochSecond() & 0xffffffffffffL, 0, false))
now.getEpochSecond() & 0xffffffffffffL, 0, authoritative))
.setExtendedPanId(newRandomBytes(random, LENGTH_EXTENDED_PAN_ID))
.setPanId(panId)
.setNetworkName(networkName)

View file

@ -64,6 +64,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserManager;
import android.os.test.TestLooper;
import android.provider.Settings;
@ -75,6 +76,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.connectivity.resources.R;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.connectivity.ConnectivityResources;
import com.android.server.thread.openthread.MeshcopTxtAttributes;
import com.android.server.thread.openthread.testing.FakeOtDaemon;
@ -90,7 +92,10 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import java.time.Clock;
import java.time.DateTimeException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicReference;
@ -534,6 +539,53 @@ public final class ThreadNetworkControllerServiceTest {
};
}
@Test
public void
createRandomizedDataset_noNetworkTimeClock_datasetActiveTimestampIsNotAuthoritative()
throws Exception {
MockitoSession session =
ExtendedMockito.mockitoSession().mockStatic(SystemClock.class).startMocking();
final IActiveOperationalDatasetReceiver mockReceiver =
ExtendedMockito.mock(IActiveOperationalDatasetReceiver.class);
try {
ExtendedMockito.when(SystemClock.currentNetworkTimeClock())
.thenThrow(new DateTimeException("fake throw"));
mService.createRandomizedDataset(DEFAULT_NETWORK_NAME, mockReceiver);
mTestLooper.dispatchAll();
} finally {
session.finishMocking();
}
verify(mockReceiver, never()).onError(anyInt(), anyString());
verify(mockReceiver, times(1)).onSuccess(mActiveDatasetCaptor.capture());
ActiveOperationalDataset activeDataset = mActiveDatasetCaptor.getValue();
assertThat(activeDataset.getActiveTimestamp().isAuthoritativeSource()).isFalse();
}
@Test
public void createRandomizedDataset_hasNetworkTimeClock_datasetActiveTimestampIsAuthoritative()
throws Exception {
MockitoSession session =
ExtendedMockito.mockitoSession().mockStatic(SystemClock.class).startMocking();
final IActiveOperationalDatasetReceiver mockReceiver =
ExtendedMockito.mock(IActiveOperationalDatasetReceiver.class);
try {
ExtendedMockito.when(SystemClock.currentNetworkTimeClock())
.thenReturn(Clock.systemUTC());
mService.createRandomizedDataset(DEFAULT_NETWORK_NAME, mockReceiver);
mTestLooper.dispatchAll();
} finally {
session.finishMocking();
}
verify(mockReceiver, never()).onError(anyInt(), anyString());
verify(mockReceiver, times(1)).onSuccess(mActiveDatasetCaptor.capture());
ActiveOperationalDataset activeDataset = mActiveDatasetCaptor.getValue();
assertThat(activeDataset.getActiveTimestamp().isAuthoritativeSource()).isTrue();
}
@Test
public void createRandomizedDataset_succeed_activeDatasetCreated() throws Exception {
final IActiveOperationalDatasetReceiver mockReceiver =