• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.wifi.p2p.nsd;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresApi;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.net.wifi.p2p.WifiP2pManager;
25 import android.net.wifi.util.Environment;
26 import android.os.Build;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 
30 import com.android.wifi.flags.Flags;
31 
32 import java.util.Locale;
33 import java.util.Objects;
34 
35 /**
36  * A class for creating a service discovery request for use with
37  * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest}
38  *
39  * <p>This class is used to create service discovery request for custom
40  * vendor specific service discovery protocol {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}
41  * or to search all service protocols {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}.
42  *
43  * <p>For the purpose of creating a UPnP or Bonjour service request, use
44  * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} respectively.
45  *
46  * {@see WifiP2pManager}
47  * {@see WifiP2pUpnpServiceRequest}
48  * {@see WifiP2pDnsSdServiceRequest}
49  */
50 public class WifiP2pServiceRequest implements Parcelable {
51 
52     /**
53      * Service discovery protocol. It's defined in table63 in Wi-Fi Direct specification.
54      */
55     private int mProtocolType;
56 
57     /**
58      * The length of the service request TLV.
59      * The value is equal to 2 plus the number of octets in the
60      * query data field.
61      */
62     private int mLength;
63 
64     /**
65      * Service transaction ID.
66      * This is a nonzero value used to match the service request/response TLVs.
67      */
68     private int mTransId;
69 
70     /**
71      * The hex dump string of query data for the requested service information.
72      *
73      * e.g) DnsSd apple file sharing over tcp (dns name=_afpovertcp._tcp.local.)
74      * 0b5f6166706f766572746370c00c000c01
75      */
76     private String mQuery;
77 
78     /**
79      * This field is used only when the service discovery request is using un-synchronized service
80      * discovery (USD) protocol. Refer Wi-Fi Alliance Wi-Fi Direct R2 specification section 3.7 -
81      * "Unsynchronized Service Discovery (USD)" for the details.
82      */
83     private WifiP2pUsdBasedServiceConfig mUsdServiceConfig;
84 
85     /**
86      * Service discovery request session ID (Seeker ID) for USD based service discovery.
87      * The session ID is used to match the USD based service discovery request/response frames.
88      * A nonzero ID in the range of 1 to 255 is filled in the Service descriptor attribute (SDA) -
89      * instance ID field of the service discovery request frame (Subscribe frame). The responding
90      * device copies this ID in the Service descriptor attribute (SDA) - requester instance ID
91      * field of the service discovery response frame (Publish frame).
92      * Zero by default indicates that the USD session for this service is not running.
93      */
94     private int mUsdSessionId = 0;
95 
96     /**
97      * This constructor is only used in newInstance().
98      *
99      * @param protocolType service discovery protocol.
100      * @param query The part of service specific query.
101      * @hide
102      */
103     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
WifiP2pServiceRequest(int protocolType, String query)104     protected WifiP2pServiceRequest(int protocolType, String query) {
105         validateQuery(query);
106 
107         mProtocolType = protocolType;
108         mQuery = query;
109         if (query != null) {
110             mLength = query.length()/2 + 2;
111         } else {
112             mLength = 2;
113         }
114     }
115 
116     /**
117      * This constructor is only used in parcelable.
118      *
119      * @param serviceType service discovery type.
120      * @param length the length of service discovery packet.
121      * @param transId the transaction id
122      * @param query The part of service specific query.
123      * @param usdConfig The USD based service config.
124      * @param usdSessionId The USD based service discovery request session ID.
125      */
WifiP2pServiceRequest(int serviceType, int length, int transId, String query, @NonNull WifiP2pUsdBasedServiceConfig usdConfig, int usdSessionId)126     private WifiP2pServiceRequest(int serviceType, int length,
127             int transId, String query, @NonNull WifiP2pUsdBasedServiceConfig usdConfig,
128             int usdSessionId) {
129         mProtocolType = serviceType;
130         mLength = length;
131         mTransId = transId;
132         mQuery = query;
133         mUsdServiceConfig = usdConfig;
134         mUsdSessionId = usdSessionId;
135     }
136 
137     /**
138      * Return transaction id.
139      *
140      * @return transaction id
141      * @hide
142      */
getTransactionId()143     public int getTransactionId() {
144         return mTransId;
145     }
146 
147     /**
148      * Set transaction id.
149      *
150      * @param id
151      * @hide
152      */
setTransactionId(int id)153     public void setTransactionId(int id) {
154         mTransId = id;
155     }
156 
157     /**
158      * Return wpa_supplicant request string.
159      *
160      * The format is the hex dump of the following frame.
161      * <pre>
162      * _______________________________________________________________
163      * |        Length (2)        |   Type (1)   | Transaction ID (1) |
164      * |                  Query Data (variable)                       |
165      * </pre>
166      *
167      * @return wpa_supplicant request string.
168      * @hide
169      */
getSupplicantQuery()170     public String getSupplicantQuery() {
171         StringBuffer sb = new StringBuffer();
172         // length is retained as little endian format.
173         sb.append(String.format(Locale.US, "%02x", (mLength) & 0xff));
174         sb.append(String.format(Locale.US, "%02x", (mLength >> 8) & 0xff));
175         sb.append(String.format(Locale.US, "%02x", mProtocolType));
176         sb.append(String.format(Locale.US, "%02x", mTransId));
177         if (mQuery != null) {
178             sb.append(mQuery);
179         }
180 
181         return sb.toString();
182     }
183 
184     /**
185      * Return the USD based service discovery request session ID.
186      * This ID is used to match the USD based service request/response frames.
187      *
188      * @return A nonzero ID in the range of 1 to 255 when the session is running.
189      * @hide
190      */
getUsdSessionId()191     public int getUsdSessionId() {
192         return mUsdSessionId;
193     }
194 
195     /**
196      * Set the USD based service discovery request session ID.
197      * Default value is zero.
198      *
199      * @param sessionId nonzero session ID is set when the USD session for this service is started.
200      * @hide
201      */
setUsdSessionId(int sessionId)202     public void setUsdSessionId(int sessionId) {
203         mUsdSessionId = sessionId;
204     }
205 
206     /**
207      /**
208      * Get the service information configured to discover a service using un-synchronized service
209      * discovery (USD) protocol.
210      * See {@link #WifiP2pServiceRequest(WifiP2pUsdBasedServiceConfig)}.
211      *
212      * @return A valid or not null {@link WifiP2pUsdBasedServiceConfig} if the service information
213      * is configured to discover a service using un-synchronized service discovery (USD) protocol.
214      * Otherwise, it is null.
215      */
216     @RequiresApi(Build.VERSION_CODES.BAKLAVA)
217     @FlaggedApi(Flags.FLAG_WIFI_DIRECT_R2)
218     @Nullable
getWifiP2pUsdBasedServiceConfig()219     public WifiP2pUsdBasedServiceConfig getWifiP2pUsdBasedServiceConfig() {
220         if (!Environment.isSdkAtLeastB()) {
221             throw new UnsupportedOperationException();
222         }
223         return mUsdServiceConfig;
224     }
225 
226     /**
227      * Validate query.
228      *
229      * <p>If invalid, throw IllegalArgumentException.
230      * @param query The part of service specific query.
231      */
validateQuery(String query)232     private void validateQuery(String query) {
233         if (query == null) {
234             return;
235         }
236 
237         int UNSIGNED_SHORT_MAX = 0xffff;
238         if (query.length()%2 == 1) {
239             throw new IllegalArgumentException(
240                     "query size is invalid. query=" + query);
241         }
242         if (query.length()/2 > UNSIGNED_SHORT_MAX) {
243             throw new IllegalArgumentException(
244                     "query size is too large. len=" + query.length());
245         }
246 
247         // check whether query is hex string.
248         query = query.toLowerCase(Locale.ROOT);
249         char[] chars = query.toCharArray();
250         for (char c: chars) {
251             if (!((c >= '0' && c <= '9') ||
252                     (c >= 'a' && c <= 'f'))){
253                 throw new IllegalArgumentException(
254                         "query should be hex string. query=" + query);
255             }
256         }
257     }
258 
259     /**
260      * Create a service discovery request.
261      *
262      * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}
263      * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
264      * In order to create a UPnP or Bonjour service request, use
265      * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest}
266      * respectively
267      *
268      * @param queryData hex string that is vendor specific.  Can be null.
269      * @return service discovery request.
270      */
newInstance(int protocolType, String queryData)271     public static WifiP2pServiceRequest newInstance(int protocolType, String queryData) {
272         return new WifiP2pServiceRequest(protocolType, queryData);
273     }
274 
275     /**
276      * Create a service discovery request.
277      *
278      * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}
279      * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
280      * In order to create a UPnP or Bonjour service request, use
281      * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest}
282      * respectively
283      *
284      * @return service discovery request.
285      */
newInstance(int protocolType )286     public static WifiP2pServiceRequest newInstance(int protocolType ) {
287         return new WifiP2pServiceRequest(protocolType, null);
288     }
289 
290     /**
291      * Constructor for creating a service discovery request for discovering the service using
292      * un-synchronized service discovery (USD) protocol. Refer Wi-Fi Alliance Wi-Fi Direct R2
293      * specification section 3.7 - "Unsynchronized Service Discovery (USD)" for the details.
294      *
295      * @param usdConfig See {@link WifiP2pUsdBasedServiceConfig}
296      *
297      * @return service discovery request containing USD based service configuration.
298      */
299     @RequiresApi(Build.VERSION_CODES.BAKLAVA)
300     @FlaggedApi(Flags.FLAG_WIFI_DIRECT_R2)
WifiP2pServiceRequest(@onNull WifiP2pUsdBasedServiceConfig usdConfig)301     public WifiP2pServiceRequest(@NonNull WifiP2pUsdBasedServiceConfig usdConfig) {
302         if (!Environment.isSdkAtLeastB()) {
303             throw new UnsupportedOperationException();
304         }
305         Objects.requireNonNull(usdConfig, "usdConfig cannot be null");
306         mUsdServiceConfig = usdConfig;
307     }
308 
309     @Override
equals(Object o)310     public boolean equals(Object o) {
311         if (o == this) {
312             return true;
313         }
314         if (!(o instanceof WifiP2pServiceRequest)) {
315             return false;
316         }
317 
318         WifiP2pServiceRequest req = (WifiP2pServiceRequest)o;
319 
320         /*
321          * Not compare transaction id.
322          * Transaction id may be changed on each service discovery operation.
323          */
324         return mProtocolType == req.mProtocolType
325                 && mLength == req.mLength
326                 && Objects.equals(mQuery, req.mQuery)
327                 && Objects.equals(mUsdServiceConfig, req.mUsdServiceConfig);
328    }
329 
330     @Override
hashCode()331     public int hashCode() {
332         int result = 17;
333         result = 31 * result + mProtocolType;
334         result = 31 * result + mLength;
335         result = 31 * result + (mQuery == null ? 0 : mQuery.hashCode());
336         result = 31 * result + (mUsdServiceConfig == null ? 0 : mUsdServiceConfig.hashCode());
337         return result;
338     }
339 
340     /** Implement the Parcelable interface {@hide} */
describeContents()341     public int describeContents() {
342         return 0;
343     }
344 
345     /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)346     public void writeToParcel(Parcel dest, int flags) {
347         dest.writeInt(mProtocolType);
348         dest.writeInt(mLength);
349         dest.writeInt(mTransId);
350         dest.writeString(mQuery);
351         if (Environment.isSdkAtLeastB() && Flags.wifiDirectR2()) {
352             dest.writeParcelable(mUsdServiceConfig, flags);
353             dest.writeInt(mUsdSessionId);
354         }
355     }
356 
357     /** Implement the Parcelable interface {@hide} */
358     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
359     public static final @android.annotation.NonNull Creator<WifiP2pServiceRequest> CREATOR =
360             new Creator<WifiP2pServiceRequest>() {
361                 public WifiP2pServiceRequest createFromParcel(Parcel in) {
362                     int servType = in.readInt();
363                     int length = in.readInt();
364                     int transId = in.readInt();
365                     String query = in.readString();
366                     WifiP2pUsdBasedServiceConfig config = null;
367                     int usdSessionId = 0;
368                     if (Environment.isSdkAtLeastB() && Flags.wifiDirectR2()) {
369                         config = in.readParcelable(
370                                 WifiP2pUsdBasedServiceConfig.class.getClassLoader());
371                         usdSessionId = in.readInt();
372                     }
373                     return new WifiP2pServiceRequest(servType, length, transId, query, config,
374                             usdSessionId);
375                 }
376                 public WifiP2pServiceRequest[] newArray(int size) {
377                     return new WifiP2pServiceRequest[size];
378                 }
379             };
380 }
381