1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.nsd; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresApi; 24 import android.annotation.SystemApi; 25 import android.os.Build; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 29 import com.android.net.flags.Flags; 30 import com.android.net.module.util.HexDump; 31 32 import java.util.Arrays; 33 import java.util.Collections; 34 import java.util.List; 35 import java.util.Objects; 36 37 /** 38 * The OffloadServiceInfo class contains all the necessary information the OffloadEngine needs to 39 * know about how to offload an mDns service. The OffloadServiceInfo is keyed on 40 * {@link OffloadServiceInfo.Key} which is a (serviceName, serviceType) pair. 41 * 42 * @hide 43 */ 44 @FlaggedApi(Flags.FLAG_REGISTER_NSD_OFFLOAD_ENGINE_API) 45 @SystemApi 46 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 47 public final class OffloadServiceInfo implements Parcelable { 48 @NonNull 49 private final Key mKey; 50 @NonNull 51 private final String mHostname; 52 @NonNull final List<String> mSubtypes; 53 @Nullable 54 private final byte[] mOffloadPayload; 55 private final int mPriority; 56 private final long mOffloadType; 57 58 /** 59 * Creates a new OffloadServiceInfo object with the specified parameters. 60 * 61 * @param key The key of the service. 62 * @param subtypes The list of subTypes of the service. 63 * @param hostname The name of the host offering the service. It is meaningful only when 64 * offloadType contains OFFLOAD_REPLY. 65 * @param offloadPayload The raw udp payload for hardware offloading. 66 * @param priority The priority of the service, @see #getPriority. 67 * @param offloadType The type of the service offload, @see #getOffloadType. 68 */ OffloadServiceInfo(@onNull Key key, @NonNull List<String> subtypes, @NonNull String hostname, @Nullable byte[] offloadPayload, @IntRange(from = 0, to = Integer.MAX_VALUE) int priority, @OffloadEngine.OffloadType long offloadType)69 public OffloadServiceInfo(@NonNull Key key, 70 @NonNull List<String> subtypes, @NonNull String hostname, 71 @Nullable byte[] offloadPayload, 72 @IntRange(from = 0, to = Integer.MAX_VALUE) int priority, 73 @OffloadEngine.OffloadType long offloadType) { 74 Objects.requireNonNull(key); 75 Objects.requireNonNull(subtypes); 76 Objects.requireNonNull(hostname); 77 mKey = key; 78 mSubtypes = subtypes; 79 mHostname = hostname; 80 mOffloadPayload = offloadPayload; 81 mPriority = priority; 82 mOffloadType = offloadType; 83 } 84 85 /** 86 * Creates a new OffloadServiceInfo object from a Parcel. 87 * 88 * @param in The Parcel to read the object from. 89 * 90 * @hide 91 */ OffloadServiceInfo(@onNull Parcel in)92 public OffloadServiceInfo(@NonNull Parcel in) { 93 mKey = in.readParcelable(Key.class.getClassLoader(), 94 Key.class); 95 mSubtypes = in.createStringArrayList(); 96 mHostname = in.readString(); 97 mOffloadPayload = in.createByteArray(); 98 mPriority = in.readInt(); 99 mOffloadType = in.readLong(); 100 } 101 102 @Override writeToParcel(@onNull Parcel dest, int flags)103 public void writeToParcel(@NonNull Parcel dest, int flags) { 104 dest.writeParcelable(mKey, flags); 105 dest.writeStringList(mSubtypes); 106 dest.writeString(mHostname); 107 dest.writeByteArray(mOffloadPayload); 108 dest.writeInt(mPriority); 109 dest.writeLong(mOffloadType); 110 } 111 112 @Override describeContents()113 public int describeContents() { 114 return 0; 115 } 116 117 @NonNull 118 public static final Creator<OffloadServiceInfo> CREATOR = new Creator<OffloadServiceInfo>() { 119 @Override 120 public OffloadServiceInfo createFromParcel(Parcel in) { 121 return new OffloadServiceInfo(in); 122 } 123 124 @Override 125 public OffloadServiceInfo[] newArray(int size) { 126 return new OffloadServiceInfo[size]; 127 } 128 }; 129 130 /** 131 * Get the {@link Key}. 132 */ 133 @NonNull getKey()134 public Key getKey() { 135 return mKey; 136 } 137 138 /** 139 * Get the host name. (e.g. "Android.local" ) 140 */ 141 @NonNull getHostname()142 public String getHostname() { 143 return mHostname; 144 } 145 146 /** 147 * Get the service subtypes. (e.g. ["_ann"] ) 148 */ 149 @NonNull getSubtypes()150 public List<String> getSubtypes() { 151 return Collections.unmodifiableList(mSubtypes); 152 } 153 154 /** 155 * Get the raw udp payload that the OffloadEngine can use to directly reply the incoming query. 156 * <p> 157 * It is null if the OffloadEngine can not handle transmit. The packet must be sent as-is when 158 * replying to query. 159 */ 160 @Nullable getOffloadPayload()161 public byte[] getOffloadPayload() { 162 if (mOffloadPayload == null) { 163 return null; 164 } else { 165 return mOffloadPayload.clone(); 166 } 167 } 168 169 /** 170 * Create a new OffloadServiceInfo with payload updated. 171 * 172 * @hide 173 */ 174 @NonNull withOffloadPayload(@onNull byte[] offloadPayload)175 public OffloadServiceInfo withOffloadPayload(@NonNull byte[] offloadPayload) { 176 return new OffloadServiceInfo( 177 this.getKey(), 178 this.getSubtypes(), 179 this.getHostname(), 180 offloadPayload, 181 this.getPriority(), 182 this.getOffloadType() 183 ); 184 } 185 186 /** 187 * Get the offloadType. 188 * <p> 189 * For example, if the {@link com.android.server.NsdService} requests the OffloadEngine to both 190 * filter the mDNS queries and replies, the {@link #mOffloadType} = 191 * ({@link OffloadEngine#OFFLOAD_TYPE_FILTER_QUERIES} | 192 * {@link OffloadEngine#OFFLOAD_TYPE_FILTER_REPLIES}). 193 */ getOffloadType()194 @OffloadEngine.OffloadType public long getOffloadType() { 195 return mOffloadType; 196 } 197 198 /** 199 * Get the priority for the OffloadServiceInfo. 200 * <p> 201 * When OffloadEngine don't have enough resource 202 * (e.g. not enough memory) to offload all the OffloadServiceInfo. The OffloadServiceInfo 203 * having lower priority values should be handled by the OffloadEngine first. 204 */ getPriority()205 public int getPriority() { 206 return mPriority; 207 } 208 209 /** 210 * Only for debug purpose, the string can be long as the raw packet is dump in the string. 211 */ 212 @Override toString()213 public String toString() { 214 return String.format( 215 "OffloadServiceInfo{ mOffloadServiceInfoKey=%s, mHostName=%s, " 216 + "mOffloadPayload=%s, mPriority=%d, mOffloadType=%d, mSubTypes=%s }", 217 mKey, 218 mHostname, HexDump.dumpHexString(mOffloadPayload), mPriority, 219 mOffloadType, mSubtypes.toString()); 220 } 221 222 @Override equals(Object o)223 public boolean equals(Object o) { 224 if (this == o) return true; 225 if (!(o instanceof OffloadServiceInfo)) return false; 226 OffloadServiceInfo that = (OffloadServiceInfo) o; 227 return mPriority == that.mPriority && mOffloadType == that.mOffloadType 228 && mKey.equals(that.mKey) 229 && mHostname.equals( 230 that.mHostname) && Arrays.equals(mOffloadPayload, 231 that.mOffloadPayload) 232 && mSubtypes.equals(that.mSubtypes); 233 } 234 235 @Override hashCode()236 public int hashCode() { 237 int result = Objects.hash(mKey, mHostname, mPriority, 238 mOffloadType, mSubtypes); 239 result = 31 * result + Arrays.hashCode(mOffloadPayload); 240 return result; 241 } 242 243 /** 244 * The {@link OffloadServiceInfo.Key} is the (serviceName, serviceType) pair. 245 */ 246 public static final class Key implements Parcelable { 247 @NonNull 248 private final String mServiceName; 249 @NonNull 250 private final String mServiceType; 251 252 /** 253 * Creates a new OffloadServiceInfoKey object with the specified parameters. 254 * 255 * @param serviceName The name of the service. 256 * @param serviceType The type of the service. 257 */ Key(@onNull String serviceName, @NonNull String serviceType)258 public Key(@NonNull String serviceName, @NonNull String serviceType) { 259 Objects.requireNonNull(serviceName); 260 Objects.requireNonNull(serviceType); 261 mServiceName = serviceName; 262 mServiceType = serviceType; 263 } 264 265 /** 266 * Creates a new OffloadServiceInfoKey object from a Parcel. 267 * 268 * @param in The Parcel to read the object from. 269 * 270 * @hide 271 */ Key(@onNull Parcel in)272 public Key(@NonNull Parcel in) { 273 mServiceName = in.readString(); 274 mServiceType = in.readString(); 275 } 276 /** 277 * Get the service name. (e.g. "NsdChat") 278 */ 279 @NonNull getServiceName()280 public String getServiceName() { 281 return mServiceName; 282 } 283 284 /** 285 * Get the service type. (e.g. "_http._tcp" ) 286 */ 287 @NonNull getServiceType()288 public String getServiceType() { 289 return mServiceType; 290 } 291 292 @Override writeToParcel(@onNull Parcel dest, int flags)293 public void writeToParcel(@NonNull Parcel dest, int flags) { 294 dest.writeString(mServiceName); 295 dest.writeString(mServiceType); 296 } 297 298 @Override describeContents()299 public int describeContents() { 300 return 0; 301 } 302 303 @NonNull 304 public static final Creator<Key> CREATOR = 305 new Creator<Key>() { 306 @Override 307 public Key createFromParcel(Parcel in) { 308 return new Key(in); 309 } 310 311 @Override 312 public Key[] newArray(int size) { 313 return new Key[size]; 314 } 315 }; 316 317 @Override equals(Object o)318 public boolean equals(Object o) { 319 if (this == o) return true; 320 if (!(o instanceof Key)) return false; 321 Key that = (Key) o; 322 return Objects.equals(mServiceName, that.mServiceName) && Objects.equals( 323 mServiceType, that.mServiceType); 324 } 325 326 @Override hashCode()327 public int hashCode() { 328 return Objects.hash(mServiceName, mServiceType); 329 } 330 331 @Override toString()332 public String toString() { 333 return String.format("OffloadServiceInfoKey{ mServiceName=%s, mServiceType=%s }", 334 mServiceName, mServiceType); 335 } 336 } 337 } 338