• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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