/* * Copyright (C) 2023 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.thread; import static com.android.internal.util.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.util.SparseArray; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.time.Duration; import java.util.Objects; /** * Data interface for managing a Thread Pending Operational Dataset. * *
The Pending Operational Dataset represents an Operational Dataset which will become Active in
* a given delay. This is typically used to deploy new network parameters (e.g. Network Key or
* Channel) to all devices in the network.
*
* @see ThreadNetworkController#scheduleMigration
* @hide
*/
@FlaggedApi(ThreadNetworkFlags.FLAG_THREAD_ENABLED)
@SystemApi
public final class PendingOperationalDataset implements Parcelable {
// Value defined in Thread spec 8.10.1.16
private static final int TYPE_PENDING_TIMESTAMP = 51;
// Values defined in Thread spec 8.10.1.17
private static final int TYPE_DELAY_TIMER = 52;
private static final int LENGTH_DELAY_TIMER_BYTES = 4;
@NonNull
public static final Creator {@code tlvs} can be obtained from the value of a Thread Pending Operational Dataset TLV
* (see the Thread
* specification for the definition) or the return value of {@link #toThreadTlvs}.
*
* @throws IllegalArgumentException if {@code tlvs} is malformed or contains an invalid Thread
* TLV
*/
@NonNull
public static PendingOperationalDataset fromThreadTlvs(@NonNull byte[] tlvs) {
requireNonNull(tlvs, "tlvs cannot be null");
SparseArray See the Thread
* specification for the definition of the Thread TLV format.
*/
@NonNull
public byte[] toThreadTlvs() {
ByteArrayOutputStream dataset = new ByteArrayOutputStream();
byte[] activeDatasetBytes = mActiveOpDataset.toThreadTlvs();
dataset.write(activeDatasetBytes, 0, activeDatasetBytes.length);
dataset.write(TYPE_PENDING_TIMESTAMP);
byte[] pendingTimestampBytes = mPendingTimestamp.toTlvValue();
dataset.write(pendingTimestampBytes.length);
dataset.write(pendingTimestampBytes, 0, pendingTimestampBytes.length);
dataset.write(TYPE_DELAY_TIMER);
byte[] delayTimerBytes = new byte[LENGTH_DELAY_TIMER_BYTES];
ByteBuffer.wrap(delayTimerBytes).putInt((int) mDelayTimer.toMillis());
dataset.write(delayTimerBytes.length);
dataset.write(delayTimerBytes, 0, delayTimerBytes.length);
return dataset.toByteArray();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (!(other instanceof PendingOperationalDataset)) {
return false;
} else {
PendingOperationalDataset otherDataset = (PendingOperationalDataset) other;
return mActiveOpDataset.equals(otherDataset.mActiveOpDataset)
&& mPendingTimestamp.equals(otherDataset.mPendingTimestamp)
&& mDelayTimer.equals(otherDataset.mDelayTimer);
}
}
@Override
public int hashCode() {
return Objects.hash(mActiveOpDataset, mPendingTimestamp, mDelayTimer);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{activeDataset=")
.append(getActiveOperationalDataset())
.append(", pendingTimestamp=")
.append(getPendingTimestamp())
.append(", delayTimer=")
.append(getDelayTimer())
.append("}");
return sb.toString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeByteArray(toThreadTlvs());
}
}