[Thread] fix SparseArray hash for ActiveOperationalDataset

The existing ActiveOperationalDataset#hashCode has an issue that it's
depending on the SparseArray#hasCode which doesn't override the
Object#hashCode method. The consequence is that when the
ActiveOperationalDataset is used as a key in a container, there will
be a miss even if two ActiveOperationalDataset objects have the same
content.

This commit fixes this issue by using a dedicated
byteArraySparseArrayHasCode() method which computes the content hashcode
with Arrays.deepHashCode(). Also fixes the issue that mUnknownTlvs is
not counted in hashCode().

Flag: EXEMPT trivial bugfix
Change-Id: I085d3bf0bdf4bb73bb995fc28dd3857437f9743e
This commit is contained in:
Kangping Dong 2025-06-09 20:05:49 +08:00
commit 2e49f00e29
2 changed files with 21 additions and 2 deletions

View file

@ -363,6 +363,14 @@ public final class ActiveOperationalDataset implements Parcelable {
outputStream.write(entries, 0, entries.length);
}
private static int byteArraySparseArrayHashCode(@NonNull SparseArray<byte[]> array) {
int result = 0;
for (int i = 0; i < array.size(); i++) {
result = 31 * result + deepHashCode(array.keyAt(i), array.valueAt(i));
}
return result;
}
private static boolean areByteSparseArraysEqual(
@NonNull SparseArray<byte[]> first, @NonNull SparseArray<byte[]> second) {
if (first == second) {
@ -591,14 +599,16 @@ public final class ActiveOperationalDataset implements Parcelable {
@Override
public int hashCode() {
return deepHashCode(
// SparseArray<byte[]> is not hashable
int result = byteArraySparseArrayHashCode(mChannelMask);
result = result * 31 + byteArraySparseArrayHashCode(mUnknownTlvs);
return result * 31 + deepHashCode(
mActiveTimestamp,
mNetworkName,
mExtendedPanId,
mPanId,
mChannel,
mChannelPage,
mChannelMask,
mPskc,
mNetworkKey,
mMeshLocalPrefix,

View file

@ -696,6 +696,15 @@ public final class ActiveOperationalDatasetTest {
assertThat(dataset.getSecurityPolicy().getFlags()).isEqualTo(new byte[] {(byte) 0xff});
}
@Test
public void hashCode_datasetsWithUnknownTlvs_hashCodeEquals() {
final byte[] datasetWithUnknownTlvs = addTlv(VALID_DATASET_TLVS, "AA01FFBB020102");
var dataset1 = ActiveOperationalDataset.fromThreadTlvs(datasetWithUnknownTlvs);
var dataset2 = ActiveOperationalDataset.fromThreadTlvs(datasetWithUnknownTlvs);
assertThat(dataset1.hashCode()).isEqualTo(dataset2.hashCode());
}
@Test
public void securityPolicy_invalidRotationTime_throwsIllegalArguments() {
assertThrows(