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